There exist ways for to modify view from another thread, using the SynchronizationContext.
Please see this example:
private void Button_Click(object sender, RoutedEventArgs e)
{
var sync = SynchronizationContext.Current;
BackgroundWorker w = new BackgroundWorker();
w.DoWork+=(_, __)=>
{
//sync.Post(p => { button.Content = "Working"; }, null);
int j = 0;
for (int i = 0; i < 10; i++)
{
j++;
sync.Post(p => { button.Content = j.ToString(); }, null);
Thread.Sleep(1000);
}
sync.Post(p => { button.Background = Brushes.Aqua; button.Content = "Some Content"; }, null);
};
w.RunWorkerAsync();
}
And this is the view:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="button" Content="Some Content" Click="Button_Click"/>
</Grid>
</Window>
This code, updates several times the view (a button in this case). I think this solve your initial question.
----EDIT----
This is a better way of using this idea: I propose to create a method like this in a base view model:
public void LockAndDoInBackground(Action action, string text, Action beforeVisualAction = null, Action afterVisualAction = null)
{
if (IsBusy)
return;
var currentSyncContext = SynchronizationContext.Current;
ActiveThread = new Thread((_) =>
{
currentSyncContext.Send(t =>
{
IsBusy = true;
BusyText = string.IsNullOrEmpty(text) ? "Wait please..." : text;
if (beforeVisualAction != null)
beforeVisualAction();
}, null);
action();
currentSyncContext.Send(t =>
{
IsBusy = false;
BusyText = "";
if (afterVisualAction != null)
afterVisualAction();
}, null);
});
ActiveThread.Start();
}
In this way any child view model can use this for excecuting big amount of data processing, and the UI does not get freeze. IsBusy
and BusyText
are the view models variables wich are bound to the View Wait Message and the Visibility of a Wait Element.
This is an example of use in a child view model's command:
private RelayCommand _SomeCommand;
public RelayCommand SomeCommand
{
get { return _SomeCommand ?? (_SomeCommand = new RelayCommand(ExecuteSomeCommand, CanExecuteSomeCommand)); }
}
private void ExecuteSomeCommand()
{
Action t = ()=>
{
//some action
};
LockAndDoInBackground(t, "Generating Information...");
}
private bool CanExecuteSomeCommand()
{
return SelectedItem != null;
}
Hope this will become a more clear example.