C# 在不同ViewModel之间共享数据
我正在尝试开发一个简单的MVVM项目,它有两个窗口:C# 在不同ViewModel之间共享数据,c#,wpf,mvvm,C#,Wpf,Mvvm,我正在尝试开发一个简单的MVVM项目,它有两个窗口: 第一个窗口是文本编辑器,我在其中绑定一些属性,如FontSize或BackgroundColor: 其DataContext是MainWindowViewModel: public class MainWindowViewModel : BindableBase { public int EditorFontSize { get { return _editorFontSize; }
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
我认为我应该使用:
谢谢我已经用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?调用(此,