我有两个关于ViewModel之间通信的问题。
我正在开发一个客户管理计划。我正在使用Laurent Bugnion的MVVM Light框架。
在主页面中,有一个客户列表。当点击每个客户时,子窗口会显示有关该客户的信息。用户应该能够同时打开多个子窗口并比较客户之间的信息。如何以MVVM友好的方式将客户对象从主页面的ViewModel传递到子窗口的ViewModel?
在显示客户信息的子窗口中,有许多选项卡,每个选项卡显示不同的信息区域。我为每个标签创建了单独的ViewModel。如何在每个选项卡的视图模型之间共享当前客户信息?
非常感谢!
答案 0 :(得分:0)
在我的项目中,我也将ViewModels传递给子窗口。我在我的子窗口的代码后面为ViewModel创建了一个依赖项属性,在这个属性的setter中,我将ViewModel传递给了我的子窗口的ViewModel。这意味着您只是为您的子窗口创建一个单独的ViewModel类。
要回答第二个问题,您可以让子窗口的ViewModel包含每个选项卡关注的属性,但是它们的数据上下文仍然与子窗口的数据上下文相同,因此它们可以访问共享属性。这实际上非常简单,因为它们会自动获取子窗口的数据上下文。
以下是一个说明上述两个概念的例子。
子窗口视图 DetailsWindow.xaml (请注意,我已经养成了命名我的子窗口视图的习惯* Window.xaml而不是* View.xaml)
<controls:ChildWindow x:Class="DetailsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:Views="clr-namespace:Views"
Title="Details"
DataContext="{Binding DetailsWindowViewModel, Source={StaticResource Locator}}"
>
<Grid>
<sdk:TabControl>
<sdk:TabItem Header="First Tab" Content="{Binding FirstTabContent}" />
<sdk:TabItem Header="Second Tab" Content="{Binding SecondTabContent}" />
</sdk:TabControl>
</Grid>
</controls:ChildWindow>
DetailsWindow.xaml.cs 后面的子窗口视图代码及其界面 IDetailsWindow.cs
public partial class DetailsWindow : ChildWindow, IDetailsWindow
{
private IDetailsWindowViewModel ViewModel
{
get { return this.DataContext as IDetailsWindowViewModel; }
}
public DetailsWindow()
{
InitializeComponent();
}
#region Customer dependency property
public const string CustomerViewModelPropertyName = "Customer";
public ICustomerViewModel Customer
{
get
{
return (ICustomerViewModel)GetValue(CustomerViewModelProperty);
}
set
{
SetValue(CustomerViewModelProperty, value);
if (ViewModel != null)
{
ViewModel.Customer = value;
}
}
}
public static readonly DependencyProperty CustomerViewModelProperty = DependencyProperty.Register(
CustomerViewModelPropertyName,
typeof(ICustomerViewModel),
typeof(CustomerDetailsWindow),
null);
#endregion
}
public interface IDetailsWindow
{
ICustomerViewModel Customer { get; set; }
void Show();
}
子窗口视图模型 DetailsWindowViewModel.cs 及其界面 IDetailsWindowViewModel
public class DetailsWindowViewModel : ViewModelBase, IDetailsWindowViewModel
{
public DetailsWindowViewModel(IMessenger messenger)
: base(messenger)
{
}
#region Properties
#region Customer Property
public const string CustomerPropertyName = "Customer";
private ICustomerViewModel _customer;
public ICustomerViewModel Customer
{
get { return _customer; }
set
{
if (_customer == value)
return;
var oldValue = _customer;
_customer = value;
RaisePropertyChanged(CustomerPropertyName, oldValue, value, true);
}
}
#endregion
#region FirstTabContent Property
public const string FirstTabContentPropertyName = "FirstTabContent";
private FrameworkElement _firstTabContent;
public FrameworkElement FirstTabContent
{
get { return _firstTabContent; }
set
{
if (_firstTabContent == value)
return;
_firstTabContent = value;
RaisePropertyChanged(FirstTabContentPropertyName);
}
}
#endregion
#region SecondTabContent Property
public const string SecondTabContentPropertyName = "SecondTabContent";
private FrameworkElement _secondTabContent;
public FrameworkElement SecondTabContent
{
get { return _secondTabContent; }
set
{
if (_secondTabContent == value)
return;
_secondTabContent = value;
RaisePropertyChanged(SecondTabContentPropertyName);
}
}
#endregion
#endregion
}
public interface IDetailsWindowViewModel
{
ICustomerViewModel Customer { get; set; }
FrameworkElement FirstTabContent { get; set; }
FrameworkElement SecondTabContent { get; set; }
void Cleanup();
}
您可以像这样从 MainPageViewModel.cs 中显示子窗口。
public class MainViewModel : ViewModelBase, IMainViewModel
{
private readonly IDetailsWindow _detailsWindow;
public MainViewModel(IMessenger messenger, IDetailsWindow DetailsWindow)
: base(messenger)
{
_detailsWindow = DetailsWindow;
}
private void DisplayCustomerDetails(ICustomerViewModel customerToDisplay)
{
_detailsWindow.Customer = customerToDisplay;
_detailsWindow.Show();
}
}
请注意,我为所有视图模型和子窗口创建接口,并在ViewModelLocator中使用DI / IoC容器,以便为我注入所有ViewModel的依赖项。你不必这样做,但我喜欢它是如何工作的。