【问题标题】:Share DataContext between MainWindows and UserControl在 MainWindows 和 UserControl 之间共享 DataContext
【发布时间】:2016-07-27 09:30:15
【问题描述】:

我想知道是否可以在 Windows 之间共享数据上下文并且是 C#/WPF 中的 UserControl。

我有一个这样的主窗口(未完成):

MainWindow.xaml:

<Window x:Class="MyProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProject"
        xmlns:v="clr-namespace:MyProject.Views"
        mc:Ignorable="d"
        Title="MyProject" >
    <Window.DataContext>
        <local:MainViewModel/>        
    </Window.DataContext>
    <Grid>
        <v:GenerateView/>
        <v:ReadView/>
    </Grid>
</Window>

MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    #region Properties
    #endregion

    #region Fields
    #endregion

    #region Constructor
    public MainViewModel()
        : base()
    {
    }
    #endregion

    #region Methods
    #endregion

    #region Commands
    #endregion
}

根据未来的参数,我将显示我的视图 GenerateView 或 ReadView。实际上我正在开发 UserControl GenerateView,但我想知道我是否可以使用相同的 Datacontext。

根据that post,我是这样开始的:

<UserControl x:Class="MyProject.Views.GenerateView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:MyProject.Views"
         xmlns:p="clr-namespace:MyProject.Properties"
         xmlns:MyProject="clr-namespace:MyProject" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}">
    <Grid>
    </Grid>
</UserControl>

但它不起作用,当我尝试访问GenerateView中的Datacontext时,它为空。

编辑:

我忘记了部分代码:

public partial class GenerateView : UserControl
{
    private MainViewModel Context
    {
        get
        {
            return DataContext as MainViewModel;
        }
    }

    public GenerateView()
    {
        InitializeComponent();
        Context.PropertyChanged += Context_PropertyChanged;
    }

    private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        //Action to perform
    }
}

Context.PropertyChanged += Context_PropertyChanged; 行抛出异常,因为 Datacontext 为空。

【问题讨论】:

  • 如果没有明确设置,DataContext 会向下继承到所有子控件。尝试从您的 UserControls 中删除它并仅在 Window 中设置它。
  • 另外,在调用构造函数之前不会设置 DataContext。使用 DataContextChanged 事件了解它的设置时间。
  • @Nudity 我从 UserControls 中删除了它,并进行了测试。 DataContext 在构造函数 GenerateView 上为 null,但在 MainViewModel 中的 InitializeComponent 之后,DataContext 在两者上都是正确的。但我无法在我的 UserControl @Andrew Perfect 上设置 Context.PropertyChanged

标签: c# wpf datacontext


【解决方案1】:

为 Window 及其子用户控件重用视图模型的主要要求是什么? 这没有意义。两者都有共同点吗?

在我看来,创建MainWindowViewModel 并创建SubViewModel 以供用户控制。 在 MainWindowViewModel 中创建子视图模型的实例并使用 DataContext.SubViewModel 访问它们。

通过这样做,您可以很好地维护代码和应用程​​序,并保持编码标准并拥有一个无复杂性的视图模型。如果您只是为了可重用性而混淆所有内容,那么您可能违反了 MVVM 模式。让不同的视图/窗口有自己的视图模型,因为它们根本不一样。

如果两者相似,那么您可以使用Dependency Properties 创建可重复使用的控件。

【讨论】:

  • 我的 MainWindows 是一个空窗口。我的应用程序用于生成或读取图像。我有一个带有 IHM 的 UserControl 用于读取(ReadView),另一个用于生成(GenerateView)。两个用户控件都使用相同的文件/属性和一些常用方法。我刚开始设计我的应用程序,我可以更改它。这就是为什么我问我的问题,我想尊重 MVVM 模式,你的回答似乎很有趣。有没有合适的方法来创建类似的东西:MainWindowViewModel 具有公共字段/方法,GenerateViewModelReadViewModel 从 main 继承?
  • @A.Pissicat:是的。这显然是可能的。这就是我所说的。您可以拥有一个父视图模型。但是您不能继承视图模型。也许如果您有两个视图共同使用依赖属性来拥有可重用的视图。这样您就可以在要更改数据时更新这些属性。如果所有属性都相同,您可以使用 1 个视图而不是 2 个视图,并相应地更改数据。
【解决方案2】:

我通常在我的Window 中设置DataContext

public class MainWindow : Window
{
   InitializeComponent();
   ViewModel vm = new ViewModel();
   this.DataContext = vm;
}

或者有时更高级:

我向我的 ViewModel 添加了一个静态属性:

public static ViewModel Instance {get; set;}

public class MainWindow : Window
{
   InitializeComponent();
   if(ViewModel.Instance == null)
   {
       ViewModel.Instance = new ViewModel();           
   }
   this.DataContext = ViewModel.Instance;
}

【讨论】:

  • 不知道将 ViewModel 创建为 Singleton 是不是更容易?
  • @A.Pissicat 取决于您的用例。我更喜欢始终使用相同的实例,而不是每次都创建新的 VM。当涉及到很多绑定时,我不想全部使用默认值 - 相反,我最终得到了 VM 的值。
【解决方案3】:

根据 Andrew 的评论,我已经解决了我的问题:

公共部分类 GenerateView : UserControl { 私有 MainViewModel 上下文 { 得到 { 返回 DataContext 作为 MainViewModel; } }

public GenerateView()
{
    InitializeComponent();
    DataContextChanged += GenerateView_DataContextChanged;
}

private void GenerateView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (Context != null)
        Context.PropertyChanged += Context_PropertyChanged;
}
private void Context_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    //Action to perform
}

}

我从我的用户控件中删除了DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}"

【讨论】:

    【解决方案4】:

    可以使用视图优先的方法。 您首先为设计目的定义设计上下文。

    <UserControl x:Class="MyProject.Views.CustomView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:MyProject.Views"
         xmlns:p="clr-namespace:MyProject.Properties"
         xmlns:MyProject="clr-namespace:MyProject" 
         mc:Ignorable="d"
         d:DataContext="{d:DesignInstance Type=vm:MyViewModel}"
         d:DesignHeight="300" d:DesignWidth="300">
      <Grid>
         .....
      </Grid>
    </UserControl>
    

    然后将用户控件绑定到主窗口的数据上下文

    <Window x:Class="MyProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProject"
        xmlns:v="clr-namespace:MyProject.Views"
        mc:Ignorable="d"
        Title="MyProject" >
    <Window.DataContext>
        <local:MyViewModel/>        
    </Window.DataContext>
    <Grid>
        <v:CustomView/>
    </Grid>
    </Window>
    

    那么用户控件会自动继承其父控件的datacontext。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-20
      • 2014-05-30
      相关资源
      最近更新 更多