无法从其他类中的 ViewModel 更新 UI [英] Can't update UI from ViewModel in another classes
问题描述
我创建了一个需要大量访问 UI 控件的应用程序,现在我首先做的是创建一个可扩展的界面,特别是我创建了不同的控件作为 UserControl
和一个类 ViewModel
管理此控件的所有方法以更新 UI.实际上在 Main
线程中都运行良好.特别是以下场景完美运行:
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:
主窗口 XAML
xmlns:MyControls="clr-namespace:HeavyAPP"
...
<!-- I use the control in the following way: -->
<Grid>
<MyControls:Scheduler x:Name="Sc"/>
</Grid>
例如 Scheduler
控件包含此 Data Binding
:
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 结构
public class ViewModelClass : INotifyPropertyChanged
{
private CScheduler scheduler;
public ViewModelClass()
{
scheduler = new Scheduler();
}
public string NextSynchronization
{
get
{
return scheduler.GetNextSync();
}
}
}
你如何在 ViewModel
中看到我有一个 Scheduler
控件的实例和一个名为 NextSyncrhonization
的 property
code> 作为binding
,所以这个属性返回一个来自控件实例的方法的结果.
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.
为了在 MainWindow
中使用它,我做了以下操作:
For use this in the MainWindow
I did the following:
public MainWindow()
{
ViewModelClass viewModel = new ViewModelClass();
DataContext = viewModel;
}
这会自动填充控件属性.现在的问题是我使用 BackgroundWorker
来执行一些任务,我需要的是使用来自不同类的 MainWindow
的 DataContext
,(不是 Window,但是类).
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"}));
现在 SynchronizationLog
是将文本附加到控件的另一个属性,只是为了精确,是这样的:
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();
}
}
这是 INotifyPropertyChanged 的实现:
`public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}`
这仅在 MainWindow
中有效,但在外部类中我无法更新 UI,我做错了什么?
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.
推荐答案
尝试以下操作:
按如下方式扩展您的 ViewModel:
extend your ViewModel as follow:
public class ViewModelClass : INotifyPropertyChanged
{
private CScheduler scheduler;
//Add this:
public static ViewModelClass Instance {get; set;} //NEW
public ViewModelClass()
{
scheduler = new Scheduler();
}
public string NextSynchronization
{
get
{
return scheduler.GetNextSync();
}
}
}
这会将您在 xaml.cs 中的代码更改为:
This changes your code in the xaml.cs to:
public MainWindow()
{
ViewModelClass.Instance = new ViewModelClass();
DataContext = viewModel.Instance;
}
在您的外部代码中,您不要创建 ViewModelClass
的新实例 - 而是使用现有的实例:
In your external code you then DONT create a new Instance of the ViewModelClass
- instead you use the existing one:
[...].Dispatcher.Invoke(() =>
{
if(ViewModelClass.Instance != null)
{
//Why you need the "var datacontext" in your example here ?
ViewModelClass.Instance.SynchronizationLog = "this is a test from other thread"
}
}));
基本上,您在这里所做的是从您的视图模型之外在您的 ViewModel 中设置一个属性.这可以从任何地方完成.
Basically what you do here is setting a property in your ViewModel from outside of your viewModel. This can be done from everywhere.
您的方法有何不同:
- 我们不会创建 ViewModel 的新实例(UI 中的不同绑定不再重置)
- 我们创建了一个
Instance
,所以一次只能有一个viewModel
- We dont create a new Instance of the ViewModel (different bindings in the UI aren't resetted anymore)
- We created an
Instance
so there can always be ONLY ONE viewModel at a time
这篇关于无法从其他类中的 ViewModel 更新 UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!