在不同的ViewModel之间共享数据

gan*_*o55 7 c# wpf mvvm

我正在尝试开发一个简单的MVVM项目,它有两个窗口:

  1. 第一个窗口是文本编辑器,我在其中绑定一些属性,如:FontSizeBackgroundColor:

    <TextBlock FontSize="{Binding EditorFontSize}"></TextBlock>

DataContextMainWindowViewModel:

public class MainWindowViewModel : BindableBase
{     
    public int EditorFontSize
    {
        get { return _editorFontSize; }
        set { SetProperty(ref _editorFontSize, value); }
    } 
.....
Run Code Online (Sandbox Code Playgroud)
  1. 第二个窗口是选项窗口,我有一个用于更改字体大小的滑块:

<Slider Maximum="30" Minimum="10" Value="{Binding EditorFontSize }" ></Slider>

DataContextOptionViewModel:

public class OptionViewModel: BindableBase
{     
    public int EditorFontSize
    {
        get { return _editorFontSize; }
        set { SetProperty(ref _editorFontSize, value); }
    }
.....
Run Code Online (Sandbox Code Playgroud)

我的问题是我必须在选项窗口中获取滑块的值,然后我必须使用此值修改我的TextBlock的FontSize属性.但我不知道如何将OptionViewModel的字体大小发送到MainViewModel.

我认为我应该使用:

  1. 共享模型
  2. MainWindowViewModel中的模型以及OptionViewModel中此模型的ref
  3. 其他系统,如通知,消息......

我希望你能帮助我.这是我的第一个MVVM项目,英语不是我的主要语言:S

谢谢

Roe*_*elF 7

另一种选择是将这种"共享"变量存储在SessionContext某种类中:

public interface ISessionContext: INotifyPropertyChanged 
{
    int EditorFontSize { get;set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,将它注入到您的视图模型中(您正在使用依赖注入,对吗?)并注册到该PropertyChanged事件:

public class MainWindowViewModel 
{
    public MainWindowViewModel(ISessionContext sessionContext)
    {
        sessionContext.PropertyChanged += OnSessionContextPropertyChanged;        
    }

    private void OnSessionContextPropertyChanged(object sender, PropertyChangedEventArgs e) 
    {
        if (e.PropertyName == "EditorFontSize")
        {
            this.EditorFontSize = sessionContext.EditorFontSize;
        }
    }       
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*pUp 6

在视图模型和许多要点之间进行通信的方法有很多,最重要的是这一点.你可以看到它是如何完成的:

在我看来,最好的方法是使用框架EventAggregator模式Prism.Prism简化了MVVM模式. 但是,如果您还没有使用过Prism,可以使用Rachel Lim的教程--Rachel Lim的EventAggregator模式的简化版本..我强烈推荐你Rachel Lim的方法.

如果您使用Rachel Lim的教程,那么您应该创建一个公共类:

public static class EventSystem
{...Here Publish and Subscribe methods to event...}
Run Code Online (Sandbox Code Playgroud)

并将事件发布到您的OptionViewModel:

eventAggregator.GetEvent<ChangeStockEvent>().Publish(
new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0” });
Run Code Online (Sandbox Code Playgroud)

然后你在另一个你的构造函数中订阅MainViewModel一个事件:

eventAggregator.GetEvent<ChangeStockEvent>().Subscribe(ShowNews);

public void ShowNews(TickerSymbolSelectedMessage msg)
{
   // Handle Event
}
Run Code Online (Sandbox Code Playgroud)

Rachel Lim的简化方法是我见过的最好的方法.但是,如果您想创建一个大型应用程序,那么您应该阅读Magnus MontinCSharpcorner的这篇文章,举例说明.

更新:对于版本Prism低于5的CompositePresentationEvent版本在版本6中已经过折旧并完全删除,因此您需要将其更改为PubSubEvent其他所有版本保持不变的版本.

  • 即将写出类似的答案,但事件聚合器模式/消息总线是要走的路.但是,我不同意将事件系统用作静态,因为这是一种反模式,使得可测试性和切换组件更加困难.事件聚合器应该(像所有其他服务和依赖项一样注入ViewModel(最好使用IoC容器,但不是强制性的) (2认同)