我创建了一个需要大量访问UI控件的应用程序,现在我首先创建的是一个可扩展的界面,特别是我创建了不同的控件UserControl
和一个类ViewModel
管理此控件的所有方法以更新UI。实际上所有工作都在Main
线程中。特别是以下场景工作完美:
MainWindow XAML
xmlns:MyControls="clr-namespace:HeavyAPP"
...
<!-- I use the control in the following way: -->
<Grid>
<MyControls:Scheduler x:Name="Sc"/>
</Grid>
所以例如Scheduler
控件包含此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
控件的实例以及property
NextSyncrhonization
为binding
,所以这个property返回控件实例的方法的结果。
要在MainWindow
使用此功能,我执行了以下操作:
public MainWindow()
{
ViewModelClass viewModel = new ViewModelClass();
DataContext = viewModel;
}
这会自动填充控件属性。现在的问题是我使用BackgroundWorker
执行某项任务,我需要的是使用来自不同类的DataContext
MainWindow
(不是Window,而是类)。
为了解决这种情况,我做了类似的事情:
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
是另一个将文本附加到Control的属性,只是为了精确,是这样的:
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,我做错了什么?
无论如何,我没有任何错误。
答案 0 :(得分:1)
尝试以下方法:
按如下方式扩展您的ViewModel:
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中的代码更改为:
public MainWindow()
{
ViewModelClass.Instance = new ViewModelClass();
DataContext = viewModel.Instance;
}
在您的外部代码中,您不必创建ViewModelClass
的新实例 - 而是使用现有的实例:
[...].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外部在ViewModel中设置属性。这可以在任何地方完成。
您的方法有何不同:
Instance
,因此一次只能有一个viewModel