gpt4 book ai didi

c# - 如何为 ChildViewModel 提供来自 MainViewModel 的数据

转载 作者:太空宇宙 更新时间:2023-11-03 15:56:04 24 4
gpt4 key购买 nike

当我设计 MVVM 应用程序时,通常会出现以下场景。一个窗口,有多个 child ,共享相同的数据源。

我正在尝试确定为所有 child 实现单一数据源的最佳方式。我可以想到 3 种选择,各有优缺点。

例子

Window 有两个子 UserControl,每个都在自己的选项卡中。

Main Window Example

UI是这样链接起来的。

XAML Design

为了保持模块化并为它们提供数据,相同的设计体现在 ViewModels 中。

ViewModel Design

MainViewModel 是这样设置的。

public class MainViewModel : ViewModelBase
{
private readonly ChildViewModelA _childViewModelA = new ChildViewModelA();
private readonly ChildViewModelB _childViewModelB = new ChildViewModelB();

public ChildViewModelA ChildViewModelA { get { return this._childViewModelA; } }
public ChildViewModelB ChildViewModelB { get { return this._childViewModelB; } }
}

MainWindow 实例化 MainViewModel 并设置子项的 DataContext。子控件绑定(bind)到数据属性。

public partial class MainWindow : Window
{
private readonly MainViewModel _viewModel = new MainViewModel();

public MainWindow()
{
InitializeComponent();
}

public MainViewModel ViewModel { get { return this._viewModel; } }
}

<Window x:Class="WpfApplication3.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WpfApplication3.View.Controls"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TabControl>
<TabItem Header="Tab 1">
<controls:ChildViewA DataContext="{Binding ViewModel.ChildViewModelA}"/>
</TabItem>
<TabItem Header="Tab 2">
<controls:ChildViewB DataContext="{Binding ViewModel.ChildViewModelB}"/>
</TabItem>
</TabControl>
</Grid>
</Window>

为了防止每个 ViewModel 从数据库中检索相同的数据,我想在 MainViewModel 中加载数据并提供 subview 。但是,有多种方法可以做到这一点。

示例 1:对 child 使用 setter 方法

public class MainViewModel : ViewModelBase
{
...
private readonly FakeDataManager _fakeDataManager = new FakeDataManager();
public MainViewModel()
{
this.CurrentPerson = _fakeDataManager.GetNextPerson();
}

private Person _currentPerson;

public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");

this.ChildViewModelA.SetPerson(this.CurrentPerson);
this.ChildViewModelB.SetPerson(this.CurrentPerson);
}
}


public class ChildViewModelA : ViewModelBase
{
private Person _currentPerson;

public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}

实现起来很容易,但很快就很难保持。没有很多代码重用。没有松耦合。不应该使用这个。

示例2:将数据放入容器

public class MainViewDataContainer : INotifyPropertyChanged
{
private Person _currentPerson;

public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}

public class MainViewModel : ViewModelBase
{
...
private readonly FakeDataManager _fakeDataManager = new FakeDataManager();
private readonly MainViewDataContainer _dataContainer = new MainViewDataContainer();

public MainViewModel()
{
this._childViewModelA = new ChildViewModelA(_dataContainer);
this._childViewModelB = new ChildViewModelB(_dataContainer);

this._dataContainer.CurrentPerson = _fakeDataManager.GetNextPerson();
}

public class ChildViewModelA : ViewModelBase
{
private readonly MainViewDataContainer _dataContainer;

public ChildViewModelA(MainViewDataContainer dataContainer)
{
this._dataContainer = dataContainer;
}

public MainViewDataContainer DataContainer { get { return this._dataContainer; } }
}

更易于维护,更多的代码重用。松耦合。

示例3:存储在MainViewModel属性中并通过接口(interface)提供给 child

public interface IMainDataProvider
{
Person CurrentPerson { get; }
}

public class MainViewModel : ViewModelBase, IMainDataProvider
{
private readonly ChildViewModelA _childViewModelA;
private readonly ChildViewModelB _childViewModelB;

private readonly FakeDataManager _fakeDataManager = new FakeDataManager();

public MainViewModel()
{
this._childViewModelA = new ChildViewModelA(this);
this._childViewModelB = new ChildViewModelB(this);

this.CurrentPerson = _fakeDataManager.GetNextPerson();
}

private Person _currentPerson;

public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}

public class ChildViewModelA : ViewModelBase
{
private readonly IMainDataProvider _dataProvider;

public ChildViewModelA(IMainDataProvider dataProvider)
{
this._dataProvider = dataProvider;
}

public IMainDataProvider DataProvider { get { return this._dataProvider; } }
}

再次更易于维护,代码重用更多。松耦合。

示例 3 似乎是最佳解决方案,但这是真的吗?你怎么看这个?有没有更好的方法来解决这个问题?

最佳答案

如果CurrentPerson由 ChildViewModels 和 MainView 使用是可以更改 CurrentPerson 的人。我将如何着手解决这个问题:

  1. 定义一个基础虚拟机 ChildViewModelBase : ViewModelBaseCurrentPerson属性(带有 INotifyPropertyChanged 和所有)。我所有的ChildViewModels将扩展此 VM。

  2. 使用事件聚合器 http://msdn.microsoft.com/en-us/library/ff921122.aspx .使用 EventAggregator你可以订阅CurrentPersonChanged您的事件 ChildViewModelBase .

  3. 来自您 MainViewModel一旦CurrentPerson从数据库加载,提高CurrentPersonChanged以新人作为事件参数的事件。

  4. ChildViewModelBase 中的事件处理程序中, 设置 CurrentPerson你得到的作为事件参数。

这样你的ChildViewModels就无所谓了谁在加载 Person来自数据库。今天是MainView ,明天它也可以是其他 View 。您只需要将 person 对象作为参数引发上述事件, subview 就会得到它。

关于c# - 如何为 ChildViewModel 提供来自 MainViewModel 的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23537585/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com