I've created an application that need a lot of access to UI controls, now what I did firstly is create an interface scalable, in particular I created different controls as UserControl
and one class ViewModel
that manage all method of this control for update the UI. Actually all working good in the Main
thread. In particular the followin scenario working perfect:
MainWindow XAML
xmlns:MyControls="clr-namespace:HeavyAPP"
...
<!-- I use the control in the following way: -->
<Grid>
<MyControls:Scheduler x:Name="Sc"/>
</Grid>
so for example the Scheduler
control contains this Data Binding
:
<StackPanel Orientation="Horizontal">
<Label x:Name="NextSync" Content="{Binding NextSynchronization, IsAsync=True}" ></Label>
</StackPanel>
ViewModel structure
public class ViewModelClass : INotifyPropertyChanged
{
private CScheduler scheduler;
public ViewModelClass()
{
scheduler = new Scheduler();
}
public string NextSynchronization
{
get
{
return scheduler.GetNextSync();
}
}
}
How you can see in the ViewModel
I've an instance of the Scheduler
control and a property
called NextSyncrhonization
as the binding
, so this property return a result from the method of the control instance.
For use this in the MainWindow
I did the following:
public MainWindow()
{
ViewModelClass viewModel = new ViewModelClass();
DataContext = viewModel;
}
this automatically fill the control property. Now the problem's that I use a BackgroundWorker
for perform some task, what I need is use the DataContext
of MainWindow
from different classes, (not Window, but classes).
For solve this situation I though to do something like this:
MainWindow.AppWindow.Sc.SyncLog.Dispatcher.Invoke(
new Action(() =>
{
ViewModelClass viewModel = new ViewModelClass();
var dataContext = System.Windows.Application.Current.MainWindow.DataContext;
dataContext = viewModel;
viewModel.SynchronizationLog = "this is a test from other thread"}));
now SynchronizationLog
is another property that append the text to the Control, just for precision, is this:
private string _text;
public string SynchronizationLog
{
get
{
return _text += _text;
}
set
{
_text = value;
OnPropertyChanged();
}
}
this is the implementation of INotifyPropertyChanged:
`public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}`
this working only in the MainWindow
, but in the external classes I can't update the UI, what am I doing wrong?
I reiceve no error, anyway.
Try the following:
extend your ViewModel as follow:
This changes your code in the xaml.cs to:
In your external code you then DONT create a new Instance of the
ViewModelClass
- instead you use the existing one:Basically what you do here is setting a property in your ViewModel from outside of your viewModel. This can be done from everywhere.
What is different to your approach:
Instance
so there can always be ONLY ONE viewModel at a time