在MainWindows和UserControl之间共享DataContext

时间:2016-07-27 09:30:16

标签: c# wpf datacontext

我想知道是否可以在Windows之间共享datacontext并且是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为null。

4 个答案:

答案 0 :(得分:3)

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

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

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

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

答案 1 :(得分:1)

我通常在DataContext

中设置Window
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;
}

答案 2 :(得分:0)

根据安德鲁的评论,我有解决问题的方法:

公共部分类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
}

}

我从UserControl中删除了DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyProject:MainWindow}}}"

答案 3 :(得分:0)

可以使用 View first 方法。 首先为设计目的定义设计上下文。

<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>

那么用户控件将自动继承其父控件的数据上下文。