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

ioekq8ef  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(134)

我已经创建了一个应用程序,需要大量的访问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控件的示例和一个名为NextSyncrhonizationproperty作为binding,所以这个属性从控件示例的方法返回一个结果。
为了在MainWindow中使用它,我做了以下操作:

public MainWindow()
{
    ViewModelClass viewModel = new ViewModelClass();
    DataContext = viewModel;
}

这将自动填充控件属性。现在的问题是,我使用一个BackgroundWorker来执行一些任务,我需要的是使用不同类的DataContextMainWindow(不是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,我做错了什么?
不管怎样,我不认为有什么错误。

lfapxunr

lfapxunr1#

尝试以下操作:
如下扩展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中的不同绑定不再重置)
1.我们创建了一个Instance,因此一次只能有一个viewModel

相关问题