无法从其他类中的 ViewModel 更新 UI [英] Can't update UI from ViewModel in another classes

查看:28
本文介绍了无法从其他类中的 ViewModel 更新 UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个需要大量访问 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 控件的实例和一个名为 NextSyncrhonizationpropertycode> 作为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 来执行一些任务,我需要的是使用来自不同类的 MainWindowDataContext,(不是 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.

您的方法有何不同:

  1. 我们不会创建 ViewModel 的新实例(UI 中的不同绑定不再重置)
  2. 我们创建了一个Instance,所以一次只能有一个viewModel
  1. We dont create a new Instance of the ViewModel (different bindings in the UI aren't resetted anymore)
  2. We created an Instance so there can always be ONLY ONE viewModel at a time

这篇关于无法从其他类中的 ViewModel 更新 UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆