ViewModel 之间的通信

发布于 2024-09-25 00:48:48 字数 357 浏览 0 评论 0原文

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

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

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

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

多谢!

I have two questions regarding communication between ViewModels.

I am developing a customer management program. I'm using Laurent Bugnion's MVVM Light framework.

  1. In the main page, there's a list of customers. when each customer is clicked, a child windows shows up with information about that customer. the user should be able to open up multiple child windows at the same time and compare information between customers. how do you pass customer object from the main page's ViewModel to the child window's ViewModel in an MVVM-friendly fashion?

  2. In the child window that shows customer information, there are a number of tabs, each showing different areas of information. I've created separate ViewModels for each of the tabs. how can you share the current customer information between each tab's viewmodels?

Thanks a lot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

止于盛夏 2024-10-02 00:48:48

在我的项目中,我也将 ViewModel 传递给子窗口。我在子窗口的代码后面为 ViewModel 创建一个依赖属性,并在该属性的设置器中将 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 的依赖项。你不必这样做,但我喜欢它的工作方式。

In my project I'm passing ViewModels to child windows too. I create a dependency property for the ViewModel in my child window's code behind and in the setter of this property I pass the ViewModel along to my child window's ViewModel. This means you're creating a separate ViewModel class just for your child window.

To answer your second question, you could have your child window's ViewModel contain properties that each tab cares about, but have their data context still be the same as the child window's data context so they have access to shared properties. This is actually very easy since they automatically get the child window's data context.

Here's an example illustrating the two concepts above.

The child window view DetailsWindow.xaml (note that I've gotten in the habit of naming my child window views *Window.xaml instead of *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>

The child window view's code behind DetailsWindow.xaml.cs and its interface 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();
}

The child window view model DetailsWindowViewModel.cs and its interface 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();
}

And you can show the child window from your MainPageViewModel.cs like this.

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();
    }
}

Note that I create interfaces for all of my view models and child windows and I use an DI/IoC container in my ViewModelLocator so that all of my ViewModels' dependencies are injected for me. You don't have to do this, but I like how it works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文