无法从其他类中的ViewModel更新UI

时间:2016-05-19 10:22:31

标签: c# wpf xaml mvvm

我创建了一个需要大量访问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 NextSyncrhonizationbinding,所以这个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,我做错了什么?

无论如何,我没有任何错误。

1 个答案:

答案 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中设置属性。这可以在任何地方完成。

您的方法有何不同:

  1. 我们不创建ViewModel的新实例(UI中的不同绑定不再被重置)
  2. 我们创建了Instance,因此一次只能有一个viewModel
相关问题