-2

Edit: Ok, after building a minimal example to reproduce the error I have to admit that it's working (Create custom object in Timer.Elapsed, update Collection in ViewModel via Invoke and one way bind readonly GUI dependency property via DataPiping in DataTemplate to ViewModel. All that without freezing the newly created objects). Nevertheless my real application is not working and I have to find the error somewhere else.

Edit2: Ok, I found the basic problem. My custom object contains a Brush property, which is a DependencyObject and needs to be created on the main thread. I think I can solve that by either freezing only the brush or simply not using the DependencyObject in my custom object. Thanks again guys, learned alot!

Thank you guys for pushing me into creating that minimal example, I really thought this is some kind of design/pattern problem which I don't get. When I found the actual problem in my real application and can't solve it myself i'll come back - with an code example :D

I have a kind of basic question I couldn't find an answer for.

What I basically want to do is:

I have a ViewModel with a ObservableCollection of own objects. This ObservableCollection is bound to an ItemsControl and the Items are displayed based on several DataTemplates. Some of these DataTemplates are using Dmitry Tashkinov's DataPiping approach (Pushing read-only GUI properties back into ViewModel) to push UIElement dependency properties to the ViewModel. All of this works fine.

Now I'm trying to add Objects to the ObservableCollecion while LeftMouseButton is pressed (basically copy/paste the selected object based on mouse position). At first I used the OnMouseMove event but since it seems that there are some delays while adding/displaying the objects and/or refreshing the mouse position it happens that "the mouse is faster than copying objects" and I need to slightly move the mouse around the target position to keep that event firing until all objects between inital and target position are pasted. Basically this works too but has bad user experience.

All approaches to do something while pressing a key i found are based on threading in some way. I tried to use a Timer which is started on LeftMouseDown and stopped on LeftMouseUp. Into the Timer.Elapsed Event I created the new Object and tried to add it to the ObservableCollection.

The Problem is that the Timer.Elapsed Method and ObservableCollection are running on different Threads and I can't add the new object directly. If I'm invoking the collection.add method from the second thread to add the object I'm geting a XAMLParseException saying that DependencySource and DependencyObject needs to be created on same thread. Also freezing the objects is not an option since they are going to be edited later.

Is there a way to copy the object on the main thread before adding it with invoke? Or is there any other common pattern to solve that basic problem?

Sven.L
  • 45
  • 1
  • 9
  • It would be awesome if you could provide a [mcve] of your attempt so far. – mjwills Apr 19 '18 at 12:56
  • especially because there is a long way from "basic question" to "observablecollection and more than one thread plus timer" – Cee McSharpface Apr 19 '18 at 13:00
  • Ok, i have to admit the question got longer than expected ;) I'll try to build a minimal example. But basically I thought it's more likely a design question than a question specific to my code. – Sven.L Apr 19 '18 at 13:08
  • I'll post a minimal example tomorrow, actually I have a very basic working example right now but without the GUI properties pushing, so I think that's the problem. – Sven.L Apr 19 '18 at 16:06

1 Answers1

-1

The Problem is that the Timer.Elapsed Method and ObservableCollection are running on different Threads and I can't add the new object directly. If I'm invoking the collection.add method from the second thread to add the object I'm geting a XAMLParseException saying that DependencySource and DependencyObject needs to be created on same thread

The solution to this would be to either use the dispatcher to marshall the call to the ObservableCollection's Add method to the UI thread:

private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
    //...

    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        //this code gets executed on the UI thread
        yourCollection.Add(...);
    }));
}

...or use the BindingOperations.EnableCollectionSynchronization method to enable the ObservableCollection to be accessed by multiple threads:

Best/cleanest strategy to update an ObservableCollection from another thread

mm8
  • 163,881
  • 10
  • 57
  • 88