Is Dispatcher not required in MVVM patern with WPF? - wpf

I am starting a new thread and trying to update UI elements through properties defined in my View Model and I am able to do it without any error, but if I try to update UI elements through code-behind, it throws the known UI access error("The calling thread cannot access this object because a different thread owns it."). First question would be ..Whats the difference between the two approaches ? Second question would be when I would use Disptacher in ViewModel ideally ?
Code Behind
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread th = new Thread(new ThreadStart(delegate()
{
textbox.Text = "Rajib";
}
));
th.Start();
}
//inside XAML
<TextBox x:Name="textbox" Text="{Binding UserInput, Mode=TwoWay}" />
MVVM
public string UserInput
{
get { return _UserInput; }
set { _UserInput = value; OnPropertyChanged("UserInput"); }
}
//Called through a ICommand property on a button click
public void ExecuteCommand(object obj)
{
InvokeCallThroughAnonymousDelegateThread();
}
private void InvokeCallThroughAnonymousDelegateThread()
{
ThreadStart start = delegate()
{
UserInput = "Calling from diff thread";
};
new Thread(start).Start();
}

Any attempt to update the UI must be done within the dispatcher thread. However, for property change events, WPF automatically dispatches for you when the event is raised from a background thread. You can read more about this on Bea Costa's (former WPF data binding PM) blog:
http://bea.stollnitz.com/blog/?p=34
They were going to do the same for INotifyCollectionChanged events but never got around to it in prior releases. For 4.5 they will now be synchronizing collection changed events automatically in addition to INotifyPropertyChanged.

The NotifyPropertyChanged has its thread context changed by WPF through the event, but your code behind doesn't change the thread context to the UI Thread. In your codebehind, use this instead:
Task.Factory.StartNew(() =>
{
// Background work
}).ContinueWith((t) => {
// Update UI thread
}, TaskScheduler.FromCurrentSynchronizationContext());
Regarding when to use the Dispatcher directly, I have a mid-sized project where I haven't used the Dispatcher in any ViewModel. I have used it to deal with Xaml resources, weak event handling, and it is used inside of MefedMVVM and Prism, which I also use.

Related

RadBusyIndicator not showing PRISM/MEF/WPF from ViewModel

I am using MVVM/PRISM/MEF for my WPF application. It has one DataGrid with multiple records, and when one row is double clicked a separate view is added to region with multiple controls on it, the initialization of controls takes about 10 seconds for new screen, so thats why I want to show RadBusyIndicator during that time.
Following in the XAML
<!-- This is Main View -->
<!-- Module: MainModule, ViewModel: MainViewViewModel -->
<telerik:RadBusyIndicator IsBusy="{Binding IsBusy}" BusyContent="{Binding BusyContent}">
<!-- All PRISM regions are here -->
</telerik:RadBusyIndicator>
Its view model is
class MainViewViewModel : ViewModelBase
{
ImportingConstructor]
public MainViewViewModel(IEventAggregator eventAggregator, IRegionManager regionManager, IServiceLocator serviceLocator)
:base(eventAggregator, regionManager, serviceLocator)
{
eventAggregator.GetEvent<BusyStateChangedEvent>().Subscribe(OnBusyStateChanged,ThreadOption.BackgroundThread);
}
#region BusyStateChanged
private void OnBusyStateChanged(bool newState)
{
IsBusy = newState;
}
#endregion
}
And in other view when DataGrid row is double clicked ViewModelBase function is called, as follows
public class ViewModelBase
{
private NavigationItem global_navItem = null;
public virtual void OnNavigationItemChanged(NavigationItem item)
{
changeNav = true;
global_navItem = item;
//Firing event to change the state
EventAggregator.GetEvent<BusyStateChangedEvent>().Publish(true);
//Using BackgroundWorker, but its not showing any Busy Indicator as well
var bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Setting busy indicator to false
EventAggregator.GetEvent<BusyStateChangedEvent>().Publish(false);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//DisplayView function is taking too long
if (global_navItem != null) this.DisplayView(global_navItem);
}
}
public void DisplayView(NavigationItem item)
{
try
{
//This call is taking long as it initializes the View
MyCustomeUserControl view = this.ServiceLocator.GetInstance<MyCustomeUserControl>(item.viewName);
view.Region = this.Region;
}catch(Exception e)
{
}
}
Events are being fired correctly and view is displayed correctly, but my problem is that Busy indicator is not shown at all, when I double click on DataGrid row the GUI become unresponsive, and after some time the new view appears. I am in doubt that this is problem of GUI thread being busy, but what can I do to avoid this, I have used BackgroudWorker already?
EDIT
1- I am raising PropertyChanged event for IsBusy Property. and I have already tried all options for Thread in event subscription. i.e. Thread.BackgroundThread, Thread.UIThread and Thread.PublisherThread. but no change.
2- I have tested Thread.Sleep rather that DisplayView in bw_DoWork, and its showing RadBusyIndicator properly, so it means that GUI controls are being initialized in GUI thread, no matter I have created a BackgroundWorker for it.
Would the indicator appear if you use Thread.Sleep(5000) instead of this.DisplayView(global_navItem)?
I assume showing the view will use the UI thread and this will block the UI no matter you use a BackgroundWorker or not.
Edit:
As it seems like your UI loading operation blocks the UI thread and so your BusyIndicator, you can try to host one of them in a different thread. An approach is explained in this article.
Finally I have found a solution. For reference following post can be seen. I have implemented a child chrome-less window with RadBusyIndicator using the approach discussed in this post.
Creating multiple UI Threads in WPF

C# WPF class property to label

I have the following class:
class MyTimer
{
class MyTimerInvalidType : SystemException
{
}
class MyTimerNegativeCycles : SystemException
{
}
private Timer timer = new Timer(1000);
private int cycles = 0;
public int Cycle
{
get
{
return this.cycles;
}
set
{
if(value >= 0)
this.cycles = value;
else
throw new MyTimerNegativeCycles();
}
}
private void timer_Tick(object sender, ElapsedEventArgs e)
{
try
{
this.Cycle--;
}
catch
{
this.Cycle = 0;
timer.Stop();
}
}
public MyTimer()
{
this.Cycle = 20;
timer.Elapsed += new ElapsedEventHandler(timer_Tick);
timer.Start();
}
}
In my MainWindow class I have a List I add a MyTimer to when a button is pressed:
private List<MyTimer> timers = new List<MyTimer>();
private void testbtn_Click(object sender, RoutedEventArgs e)
{
timers.Add(new MyTimer());
}
I tried to pass a label to the MyTimer class as a ref and update it but that won't work (can't access UI elements from another thread).
What is a good way to show the MyTimer.Cycle in a label so that it updates everytime the value is changed?
I must be able to "bind" each MyTimer to a different label from the code (or not bind it to a label at all).
You should use the BeginInvoke or Invoke method of the Dispatcher property of your label to change anything on your label or call any of it's methods:
private void timer_Tick(object sender, ElapsedEventArgs e)
{
try
{
this.Cycle--;
this.label.Dispatcher.BeginInvoke(new Action(
() => { label.Text = this.Cycle.ToString(); } ));
}
catch
{
this.Cycle = 0;
timer.Stop();
}
}
See Remarks section of the Dispatcher class or Dispatcher property.
The easiest solution to your problem is to use DispatchTimers. Dispatch timers use the windows message queue instead of a thread to dispatch timer tick events. This will make it so you don't have cross threading issues. Just keep in mind you are no longer working on a different thread and could lockup the UI if you do anything computationally expensive. Also due to the nature of dispatching on the message queue the timing is less accurate.
In WPF, you'd have a ViewModel (C#) associated with your View (XAML).
Read up on this if you're not familiar with MVVM.
Then the ViewModel would expose a property (let's call it Cycle) on which the View would bind:
<Label Content="{Binding Cycle}" />
Then if the value in the ViewModel has to be updated from another thread, do it like this:
Application.Current.Dispatcher.Invoke(new Action(() =>
{
//Update here
}));
That will execute the update logic on the UI thread.
If you're new to WPF I'd strongly suggest that read a bit about DataBinding and Data Templating.
To start, the simplest way do display windows data in older UI models (like Windows Forms) has always been to have code in the code-behind set some property of the UI. This has changed drastically with WPF and the goal now is to have the UI look at business objects (like your MyTimer) and set the UI accordingly.
First we need to expose your business objects to the xaml of your application.
Me.DataContext = new MyTimer();
This sets the data context for the Window/UserControl to be the a new MyTimer(); Because the DataContext property is automatically based from a parent UI element to a child UI elelement (unless the child defines it's own DataContext), every element in your Window/UserControl will now have a DataContext of this object.
Next we can create a binding to a property of this object. By default all bindings are relative to the DataContext of the control from which it's located.
<Label Content="{Binding Cycle}" />
So in the previous example the binding was on the content property of the label. So in this case it will automatically set the Content to the value of the "Cycle" property from the DataContext (MyTimer)!
There is however one catch. If you run this sample as is WPF will take the value when the form loads but it won't update the label ever again! The key here to updating the UI is to implement the INotifyPropertyChanged interface.
This interface simply tells any listeners whenever a property (such as your Cycles) changes. The great thing is that Bindings automatically support this interface and will automatically propagate changes when your source implements INotifyPropertyChanged.
public class MyTimer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int cycles;
public int Cycles
{
get
{
return cycles;
}
set
{
if (cycles < 0)
{
throw new ArgumentOutOfRangeException("value", "Cycles cannot be set to a number smaller than 0.");
}
else if(value <> cycles)
{
cycles = value;
if (PropertyChanged != null)
{
PropertyChanged(Me, new PropertyChangedEventArgs("Cycles"))
}
}
}
}
//insert your constructor(s) and timer code here.
}
And voila! Your timer will now update the UI with it's cycles property.
You however also noted that you were storing your MyTimer objects in a list. If you were to instead put them inside an ObservableCollection (the default implementation of INotifyCollectionChanged - the collection variant of INotifyPropertyChanged) you can do other neat tricks:
In your Window/UserControl constructor:
ObservableCollection<MyTimer> timers = New ObservableCollection<MyTimer>();
timers.Add(New MyTimer());
DataContext = timers;
Then you can display them all at once in your xaml:
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label>
<TextBlock Text="{Binding StringFormat='Cycles Remaining: {0}'}" />
</Label>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Execute command after view is loaded WPF MVVM

I have a project based WPF and MVVM.
My project is based on a wizard containing a content control which shows my views (User Controls)
I want to execute a command after the view is loaded completely, I would like the user to see the view UI immediately after the command will be executed.
I tried using :
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding StartProgressCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But the command is executed before I see the view UI and it's not what I'm looking for.
Does anyone have an idea how should I need to implement it?
You could use the Dispatcher for this and set the priority to ApplicationIdle so that it will on execute when everything has finished
Application.Current.Dispatcher.Invoke(
DispatcherPriority.ApplicationIdle,
new Action(() =>
{
StartProgressCommand.Invoke(args);
}));
more information on the dispatcher http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx
cheers.
ste.
That's because even though technically the view is loaded (i.e: all the components are ready in memory), your app is not idle yet, and thus the UI isn't refreshed yet.
Setting a command using interaction triggers on the Loaded event is already good, as there is no better event to attach to.
Now to really wait until the UI is shown, do this in your StartProgress() (I'm assuming here that this is the name of the method that StartProgressCommand point to):
public void StartProgress()
{
new DispatcherTimer(//It will not wait after the application is idle.
TimeSpan.Zero,
//It will wait until the application is idle
DispatcherPriority.ApplicationIdle,
//It will call this when the app is idle
dispatcherTimer_Tick,
//On the UI thread
Application.Current.Dispatcher);
}
private static void dispatcherTimer_Tick(object sender, EventArgs e)
{
//Now the UI is really shown, do your computations
}
another way to do it:
define this xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" and xmlns:mi="http://schemas.microsoft.com/expression/2010/interactions" on your usercontrol XAML and add Microsoft.Expression.Interactions assembly on your project. use CallMethodAction on your trigger, just as bellow:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<mi:CallMethodAction TargetObject="{Binding}" MethodName="StartProgressCommand"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Put the triger inside the root element of your usercontrol, e.g: grid. And change your StartProgressCommand, in your ViewModel class, from command to plain old regular Method, e.g:
public void StartProgressCommand()
{
/* put your program logic here*/
}
It'll run the method exactly one time every time your user control rendered.
We use a the timer solution - i too was very dubious about this but it does seem to work fine.
public static class DispatcherExtensions
{
private static Dictionary<string, DispatcherTimer> timers =
new Dictionary<string, DispatcherTimer>();
private static readonly object syncRoot = new object();
public static void DelayInvoke(this Dispatcher dispatcher, string namedInvocation,
Action action, TimeSpan delay,
DispatcherPriority priority = DispatcherPriority.Normal)
{
lock (syncRoot)
{
RemoveTimer(namedInvocation);
var timer = new DispatcherTimer(delay, priority, (s, e) =>
{
RemoveTimer(namedInvocation);
action();
}, dispatcher);
timer.Start();
timers.Add(namedInvocation, timer);
}
}
public static void CancelNamedInvocation(this Dispatcher dispatcher, string namedInvocation)
{
lock (syncRoot)
{
RemoveTimer(namedInvocation);
}
}
private static void RemoveTimer(string namedInvocation)
{
if (!timers.ContainsKey(namedInvocation)) return;
timers[namedInvocation].Stop();
timers.Remove(namedInvocation);
}
}
Then we invoke using
Dispatcher.CurrentDispatcher.DelayInvoke("InitSomething",()=> {
DoSomething();
},TimeSpan.FromSeconds(1));
You can check IsLoaded property for view, when view is in loaded form it returns false, when view is fully loaded, this property become true.
Thanks,
Rajnikant
Have you tried binding to the ContentRendered event? It will occur after the loaded event, yet I´m not sure whether or not this is a gurantee that the UI thread has finished painting the window then.
You can Write a "Thread.Sleep(10000)" in the first line of "CommandExecute" method. Use the same loaded trigger.
if you don't want to use Thread.Sleep then you can go for "DispatcherTimer". Start a timer in your command execute method and shift all your code to timer tick event.
set your timer interval to 2 seconds, so that user will sen the UI.
I came with this solution for this one.
I wanted to use a boolean property set as true at start of work and to false at the end to allow to notify user of background work.
Basically, it uses
a DispatcherTimer to launch a method after UI render according to this
An async method wich will execute the Action passed as a parameter
Call :
this.LaunchThisWhenUiLoaded(() => { /*Stuff to do after Ui loaded here*/ });
Method :
private DispatcherTimer dispatchTimer;
private Action ActionToExecuteWhenUiLoaded;
/// <summary>
/// Handy method to launch an Action after full UI rendering
/// </summary>
/// <param name="toExec"></param>
protected void LaunchThisWhenUiLoaded(Action toExec)
{
ActionToExecuteWhenUiLoaded = toExec;
// Call UiLoaded method when UI is loaded and rendered
dispatchTimer = new DispatcherTimer(TimeSpan.Zero, DispatcherPriority.ContextIdle, UiLoaded, Application.Current.Dispatcher);
}
/// <summary>
/// Method called after UI rendered
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected async void UiLoaded(object sender, EventArgs e)
{
this.IsBusy = true;
if (ActionToExecuteWhenUiLoaded != null)
await Task.Run(ActionToExecuteWhenUiLoaded);
dispatchTimer.Stop();
this.IsBusy = false;
}
Maybe not the clean but it works as expected.

Data Binding Value not updating from other thread

I have a WPF Application where I have the following StepCount Property in my ViewModel, which implements INotifyPropertyChanged, and then I have it bound to a TextBox in my View.
public int StepCount
{
get { return _stepCount; }
set
{
_stepCount = value;
OnPropertyChanged("StepCount");
}
}
In the XAML, here is what the DataBinding looks like:
<TextBox Text="{Binding Path=StepCount}" />
This works great, and if I change the StepCount value, the Textbox value updates accordingly.
However, my issue is that I have another thread that is incrementing the StepCount, and in that case, the TextBox value is not updating. As soon as the thread ends, the Textbox value updates to the correct value.
I need the Textbox value to update everytime my other thread increments the StepCount. As it is right now, the Textbox value only shows an update after the thread finishes.
The other thread is incrementing StepCount, but the change is not being displayed in the UI until the thread ends.
Any ideas?
UPDATE
I appreciate all of the responses. This issue was puzzling because code that was previously working seemed to quit working, as was the case with these particular bindings.
When I installed VS 2011 Beta, it installs the .NET 4.5 Beta Framework, and when I uninstalled VS 2011 Beta under the suspicion that it may be causing problems, it did not uninstall the .NET 4.5 Beta Framework.
I just now uninstalled the .NET 4.5 framework and did a repair install of the .NET 4.0 framework. After completing those steps, my data bindings worked correctly, and now Textbox is correctly updating whenever another thread increments StepCount.
So, it appears, the .NET 4.5 Beta Framework may cause issues with data bindings.
I'll follow up with this by submitting an issue with Microsoft.
Thanks everyone for your responses.
As you've discovered the WPF classes that you've bound your View to in the View model operate within the UI thread.
Ideally you should change the StepCount property of your view model using the WPF Dispatcher and the Invoke command. This will marshell the call appropriately.
See this article for more information on this process.
Tested just now, and all it works ok
public partial class MainWindow : Window
{
SimpleClass simpleClass = new SimpleClass(10);
public MainWindow()
{
InitializeComponent();
DataContext = simpleClass;
}
void IncrementViewModelProperty()
{
simpleClass.StepCount += 11;
Thread.Sleep(5000);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//works the same
//Thread thread = new Thread(() => IncrementViewModelProperty());
//thread.Start();
Action act = IncrementViewModelProperty;
act.BeginInvoke(null, null);
}
}
public class SimpleClass : INotifyPropertyChanged
{
public SimpleClass(int stepCnt)
{
StepCount = stepCnt;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public int StepCount
{
get { return _stepCount; }
set
{
_stepCount = value;
NotifyPropertyChanged("StepCount");
}
}
private int _stepCount;
}
then in xaml:
<StackPanel>
<TextBlock Text="{Binding Path=StepCount, Mode=OneWay}" />
<Button Content="Increment value in separate thread" Click="Button_Click" />
</StackPanel>
BUT! if you will click the button fast and often, you exhausted thread pool and it is really would not update the property as expected.

Loading the list of items asynchronously in a WPF listbox using Dispatcher

I am working on creating a WPF solution which uses MVVM pattern to load searched items in a search control asynchronously. The search control which is a WPF usercontrol is created with a textbox to enter search text and search button and a hidden listbox which would be visible when it loads the searched items list in it. This user control is in turn embedded into another WPF view which has a treeview of certain items. This view has a view model in which the logic to load the searched items of the tree view would be loaded in the search control. All the while, this has been happening synchronously without the use of any Dispatcher call. But, after a change request, I would like to make this happen asynchronously in a different thread using Dispatcher.
Could anyone please let me know how to get handle of the Dispatcher of the Search control in the view model class so as to call BeginInvoke on it using MVVM pattern wherein my View model is not aware of the view? Any clue would be highly appreciated.
public ObservableCollection<Details> CatalogSearchResults { get; private set; }
private void ExecuteSearchCommand(object parameter)
{
CatalogSearchResults.Clear();
if (string.IsNullOrEmpty(parameter.ToString())) return;
searchtext = (string)parameter;
searchtext.Trim();
SetSearchResults();
}
private void SetSearchResults()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += LoadResults;
bw.RunWorkerCompleted += this.LoadResultsCompleted;
bw.RunWorkerAsync();
}
private void LoadResults(object sender, DoWorkEventArgs args)
{
IsSearchInProgress = true;
foreach (var category in _rootCategory.Recurse(FindChildren))
{
if (category.CommentDetails != null)
{
//limitation - there is no direct way to add range to observable collection.
//Using linq query would result in two loops rather than one.
foreach (var node in category.Details)
{
if (node.Name.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0
|| node.PrecannedText.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate { CatalogSearchResults.Add(node); });
Thread.Sleep(100);
}
}
}
}
IsSearchInProgress = false;
}
In the xaml, I am biding the Items property of the Search control to the CatalogSearchResults:
<ctrl:SearchControl x:Name="Ctrl" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Top" ToolTip="Search" Command="{Binding SearchCommand}" Grid.ColumnSpan="3"
CommandParameter="{Binding Text, RelativeSource={RelativeSource Self}}"
Items ="{Binding CatalogSearchResults}" > </ctrl:SearchControl>
Thanks,
Sowmya
Here's a simple implementation showing how to use BackgroundWorker to update objects on the UI thread while DoWork is running - in this example, there's a ListBox in the UI that's bound to FilteredItems, and ItemsSource is a property of the UserControl of type IEnumerable:
FilteredItems = new ObservableCollection<object>();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = (BackgroundWorker) sender;
var result = ItemsSource
.OfType<object>()
.Where(x => x.ToString().Contains(_FilterText));
foreach (object o in result)
{
// Pass each object found to bw_ProgressChanged in the UserState argument.
// This updates the UI as each item is found.
bw.ReportProgress(0, o);
}
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// FilteredItems is bound to the UI, but it's OK to update it here because
// the ProgressChanged event handler runs on the UI thread.
FilteredItems.Add(e.UserState);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
}
Note that calling ReportProgress every time you find an item is pretty inefficient, as you're marshalling every item found across threads with an Invoke call. Depending on how long the filtering is actually taking, it may be better to accumulate a bunch of results and pass a List<object> to bw_ReportProgress instead of just a single object.
It depends on a lot of factors (and your description is a bit confusing), but I've given a lengthy answer here that may shed some light on the matter. Basically, using the dispatcher alone will not automatically make the code multi-threaded; you'll need some real multi-threading mechanism like BackgroundWorker or the Task Parallel Library. Depending on how you have things set up and on exactly what you do in the other thread, you may indeed need to invoke some actions on the dispatcher thread - however BackgroundWorker does this automatically in most cases so I'd go with that for simple things. The Task Parallel Library also has special handling for the dispatcher, you should find more info on that on MSDN or any TPL tutorial.
The best advice I'd give if you didn't deal heavily with multi-threading until now is to gather as much information as possible on it, because, as it has been said countless times until now, multi-threading is hard! :)
Modify as necessary. 'Items' is just an observableCollection of strings exposed from the VM
private void SetSearchResults()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += LoadResults;
bw.RunWorkerCompleted += this.LoadResultsCompleted;
bw.RunWorkerAsync();
}
private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
private void LoadResults(object sender, DoWorkEventArgs args)
{
List<string> results = GetResults();
foreach (string result in results)
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal, (ThreadStart)delegate { Items.Add(result); } //Dont worry about access to modified closure in this case
Thread.Sleep(100);
}
}
In XAML
<ListBox ItemsSource={Binding Items}/>
All views in the application have the same dispatcher, you can access it with Application.Current.Dispatcher.
But anyway, you don't need the dispatcher to perform operations on a worker thread. You only need it to perform actions on the UI, because UI elements can only be accessed from the UI thread. But even then, you usually don't need to explicitly manipulate the dispatcher. You can update a property of your ViewModel from the worker thread, controls bound to this property will be updated alright, because the PropertyChanged event is automatically marshalled to the UI dispatcher.
What doesn't work is modifying an bound ObservableCollection<T> from a worker thread: you need to do it from the UI thread using Dispatcher.Invoke. You can also use a specialized ObservableCollection<T> that raises event on the UI thread.

Resources