ViewModels之间的通信

时间:2010-09-28 00:40:12

标签: mvvm viewmodel mvvm-light

我有两个关于ViewModel之间通信的问题。

我正在开发一个客户管理计划。我正在使用Laurent Bugnion的MVVM Light框架。

  1. 在主页面中,有一个客户列表。当点击每个客户时,子窗口会显示有关该客户的信息。用户应该能够同时打开多个子窗口并比较客户之间的信息。如何以MVVM友好的方式将客户对象从主页面的ViewModel传递到子窗口的ViewModel?

  2. 在显示客户信息的子窗口中,有许多选项卡,每个选项卡显示不同的信息区域。我为每个标签创建了单独的ViewModel。如何在每个选项卡的视图模型之间共享当前客户信息?

  3. 非常感谢!

1 个答案:

答案 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的依赖项。你不必这样做,但我喜欢它是如何工作的。