Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在不同ViewModel之间共享数据_C#_Wpf_Mvvm - Fatal编程技术网

C# 在不同ViewModel之间共享数据

C# 在不同ViewModel之间共享数据,c#,wpf,mvvm,C#,Wpf,Mvvm,我正在尝试开发一个简单的MVVM项目,它有两个窗口: 第一个窗口是文本编辑器,我在其中绑定一些属性,如FontSize或BackgroundColor: 其DataContext是MainWindowViewModel: public class MainWindowViewModel : BindableBase { public int EditorFontSize { get { return _editorFontSize; }

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

  • 第一个窗口是文本编辑器,我在其中绑定一些属性,如
    FontSize
    BackgroundColor

  • DataContext
    MainWindowViewModel

    public class MainWindowViewModel : BindableBase
    {     
        public int EditorFontSize
        {
            get { return _editorFontSize; }
            set { SetProperty(ref _editorFontSize, value); }
        } 
    .....
    
    public class OptionViewModel: BindableBase
    {     
        public int EditorFontSize
        {
            get { return _editorFontSize; }
            set { SetProperty(ref _editorFontSize, value); }
        }
    .....
    
  • 第二个窗口是选项窗口,其中有一个用于更改字体大小的滑块:
  • 它的
    DataContext
    选项viewmodel

    public class MainWindowViewModel : BindableBase
    {     
        public int EditorFontSize
        {
            get { return _editorFontSize; }
            set { SetProperty(ref _editorFontSize, value); }
        } 
    .....
    
    public class OptionViewModel: BindableBase
    {     
        public int EditorFontSize
        {
            get { return _editorFontSize; }
            set { SetProperty(ref _editorFontSize, value); }
        }
    .....
    
    我的问题是必须在选项窗口中获取滑块的值,然后必须使用此值修改TextBlock的FontSize属性。但是我不知道如何将字体大小从OptionViewModel发送到MainViewModel

    我认为我应该使用:

  • 共享模型
  • MainWindowViewModel中的模型和OptionViewModel中此模型的引用
  • 其他系统,如通知、消息
  • 我希望你能帮助我。这是我的第一个MVVM项目,英语不是我的主要语言:s


    谢谢

    我已经用WPF完成了一个大型MVVM应用程序。我有很多窗口,我也有同样的问题。我的解决方案可能不是很优雅,但它工作得很完美

    第一个解决方案:我完成了一个独特的ViewModel,使用分部类将其拆分为不同的文件

    所有这些文件都以以下内容开头:

    namespace MyVMNameSpace
    {
        public partial class MainWindowViewModel : DevExpress.Mvvm.ViewModelBase
        {
            ...
        }
    }
    
    我正在使用DevExpress,但是,查看您的代码时,您必须尝试:

    namespace MyVMNameSpace
    {
        public partial class MainWindowViewModel : BindableBase
        {
            ...
        }
    }
    
    第二个解决方案:无论如何,我还有两个不同的ViewModel来管理其中一些窗口。在本例中,如果有一些变量要从一个ViewModel读取到另一个ViewModel,则将这些变量设置为静态变量

    例如:

        public static event EventHandler ListCOMChanged;
        private static List<string> p_ListCOM;
        public static List<string> ListCOM
        {
            get { return p_ListCOM; }
            set 
            {
                p_ListCOM = value;
                if (ListCOMChanged != null)
                    ListCOMChanged(null, EventArgs.Empty);
            }
        }
    
    公共静态事件事件处理程序ListCOMChanged;
    私有静态列表p_ListCOM;
    公共静态列表列表
    {
    获取{return p_ListCOM;}
    设置
    {
    p_ListCOM=值;
    如果(ListCOMChanged!=null)
    ListCOMChanged(null,EventArgs.Empty);
    }
    }
    
    也许第二种解决方案更简单,并且仍然适合您的需要


    我希望这是清楚的。如果您愿意,请询问我更多详细信息。

    视图模型和许多点之间有许多沟通方式,其中哪一点最好。您可以看到它是如何完成的:

    在我看来,最好的方法是使用
    Prism
    框架的
    EventAggregator
    模式。棱镜简化了MVVM模式但是,如果您没有使用
    Prism
    ,则可以使用。我强烈推荐你雷切尔·林的方法

    如果使用Rachel Lim的教程,则应创建一个公共类:

    public static class EventSystem
    {...Here Publish and Subscribe methods to event...}
    
    并将事件发布到您的
    选项ViewModel

    eventAggregator.GetEvent<ChangeStockEvent>().Publish(
    new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0” });
    
    Rachel Lim的简化方法是我见过的最好的方法。然而,如果您想创建一个大的应用程序,那么您应该阅读本文和


    更新:对于5以后的
    Prism
    版本,CompositePresentationEvent在版本6中被折旧并完全删除,因此您需要将其更改为
    PubSubEvent
    ,其他所有内容都可以保持不变。

    在MVVM中,模型是共享数据存储。我将在
    选项model
    中保留字体大小,该选项实现了
    INotifyPropertyChanged
    。任何对字体大小感兴趣的viewmodel都会订阅
    PropertyChanged

    class OptionsModel : BindableBase
    {
        public int FontSize {get; set;} // Assuming that BindableBase makes this setter invokes NotifyPropertyChanged
    }
    
    在FontSize更改时需要更新的ViewModels中:

    internal void Initialize(OptionsModel model)
    {
        this.model = model;
        model.PropertyChanged += ModelPropertyChanged;
    
        // Initialize properties with data from the model
    }
    
    private void ModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(OptionsModel.FontSize))
        {
            // Update properties with data from the model
        }
    }
    

    另一种选择是将此类“共享”变量存储在某种类型的
    SessionContext
    -类中:

    public interface ISessionContext: INotifyPropertyChanged 
    {
        int EditorFontSize { get;set; }
    }
    
    然后,将其注入viewmodels(您正在使用依赖项注入,对吗?),并注册到
    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;
            }
        }       
    }
    

    我自己不是MVVM专业人士,但我解决过这样的问题, 拥有一个将所有其他视图模型作为属性的主类,并将该类设置为所有窗口的数据上下文,我不知道它是好是坏,但对于您的情况来说,这似乎足够了

    有关更复杂的解决方案,请参阅

    对于简单的一个

    你可以这样做

    public class MainViewModel : BindableBase
    {
        FirstViewModel firstViewModel;
    
        public FirstViewModel FirstViewModel
        {
            get
            {
                return firstViewModel;
            }
    
            set
            {
                firstViewModel = value;
            }
        }
    
        public SecondViewModel SecondViewModel
        {
            get
            {
                return secondViewModel;
            }
            set
            {
                secondViewModel = value;
            }
        }
    
        SecondViewModel secondViewModel;
    
        public MainViewModel()
        {
            firstViewModel = new FirstViewModel();
            secondViewModel = new SecondViewModel();
        }
    }
    
    现在,您必须为传递视图模型的选项窗口创建另一个构造函数

     public SecondWindow(BindableBase viewModel)
        {
            InitializeComponent();
            this.DataContext = viewModel;
        }
    
    这是为了确保两个窗口在视图模型的同一实例上工作

     public SecondWindow(BindableBase viewModel)
        {
            InitializeComponent();
            this.DataContext = viewModel;
        }
    
    现在,只要你打开第二个窗口,就用这两行

    var window = new SecondWindow((ViewModelBase)this.DataContext);
            window.Show();
    
    现在,您将第一个窗口的视图模型传递给第二个窗口,以便它们在主视图模型的相同实例上工作

    一切都完成了,只是你必须解决绑定的问题

    <TextBlock FontSize="{Binding FirstViewModel.EditorFontSize}"></TextBlock>
    <TextBlock FontSize="{Binding SecondViewModel.EditorFontSize}"></TextBlock>
    
    
    

    不必说第一个窗口的数据上下文是MainViewModel,我是WPF的新手,我已经想出了一个解决方案,我很好奇更多知识渊博的人对它的对与错的看法

    我有一个考试选项卡和一个模板选项卡。在我的简单概念证明中,我希望每个选项卡“拥有”一个
    考试
    对象,并且能够访问另一个选项卡的
    考试

    我将每个选项卡的ViewModel定义为
    static
    ,因为如果它是普通实例属性,我不知道一个选项卡如何获得另一个选项卡的实际实例。我觉得这是不对的,尽管它起作用了

    namespace Gui.Tabs.ExamsTab{
    公共类GUI考试:INotifyPropertyChanged{
    私有字符串_name=“默认考试名称”;
    公共字符串名称{
    get=>\u name;
    设置{
    _名称=值;
    OnPropertyChanged();
    }
    }
    公共事件属性更改事件处理程序属性更改;
    受保护的void OnPropertyChanged([CallerMemberName]字符串propertyName=”“){
    PropertyChanged?调用(此,