C# 在 MVVM 中绑定的首选方法、资源文件中的数据模板还是视图本身中的 DataContext?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16446747/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Preferred method for binding in MVVM, Data Template in Resources file or just DataContext in View itself?
提问by djangojazz
This one has got me stumped as I THOUGHT I looked at everything but I must be missing something. I have went off the traditional MVVM pattern from the MSDN magazine:
这个让我很难过,因为我认为我看了一切,但我一定错过了一些东西。我已经脱离了 MSDN 杂志中的传统 MVVM 模式:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
while learning MVVM. However I usually copy most of the code and then replace it as I need to but today I wanted to build something from scratch and saw that there may be more to it than I thought. MVVM appeared to not work with bindings when I used the resource dictionary but does with datacontext directly. This question ultimately wants to find other developers suggested use of binding they find.
在学习 MVVM 时。然而,我通常会复制大部分代码,然后根据需要替换它,但今天我想从头开始构建一些东西,发现它可能比我想象的要多。当我使用资源字典但直接使用数据上下文时,MVVM 似乎不适用于绑定。这个问题最终是想找其他开发者建议使用他们找到的绑定。
Summary of question is this: Why does the 'DataTemplate' in the Resource Dictionary appear to not work shown below but a direct 'DataContext' method does with a view right away for bindings?
问题摘要是这样的:为什么资源字典中的“DataTemplate”似乎不起作用,但直接的“DataContext”方法可以立即用于绑定视图?
Is it because I am doing a mixture of code behind with settings views in the code behind. Or potentially because of something else. It appears my property and it's implementation are set correct in the viewmodel if I set the 'DataContext' directly in the View's XAML, but why not in the Resource Dictionary? I thought the advantage of that method was you could set a bunch of relationships all at once. I am curious if there is some other setting need to be done to get it to work. It is curious in the main example of the MVVM method they use Data Templates yet it appears there is more to setting them up than I am doing to get their 'bindings' to work.
是不是因为我在后面的代码中混合了代码和设置视图。或者可能是因为其他原因。如果我直接在视图的 XAML 中设置“DataContext”,那么我的属性和它的实现在视图模型中设置正确,但为什么不在资源字典中设置?我认为这种方法的优点是你可以一次设置一堆关系。我很好奇是否需要进行其他设置才能使其正常工作。在他们使用数据模板的 MVVM 方法的主要示例中很奇怪,但似乎设置它们比我做的更多,以使它们的“绑定”工作。
WHAT DID NOT WORK FOR ME:
什么对我不起作用:
I attempted to do some very basic stuff in a main window xaml, leaving some of my code out to make it even simpler:
我试图在主窗口 xaml 中做一些非常基本的事情,留下我的一些代码以使其更简单:
Main Window XAML:
主窗口 XAML:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts" x:Class="WPFTesting12_2.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary Source="Resources.xaml"/>
</Window.Resources>
<Grid>
<DockPanel x:Name="dockpanel">
<Menu DockPanel.Dock="Top" Height="30">
<MenuItem Header="Charting">
<MenuItem Header="MVVMDataBound" x:Name="mnuDataBoundSeriesMVVMCharting" Click="mnuDataBoundSeriesMVVMCharting_OnClick"/>
</MenuItem>
</Menu>
<TextBlock Height="5" Background="Black" DockPanel.Dock="Top" />
<DockPanel x:Name="dockchildren" DockPanel.Dock="Bottom"/>
</DockPanel>
</Grid>
</Window>
Main Window Code Behind:
后面的主窗口代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.WindowState = WindowState.Maximized;
}
private void mnuDataBoundSeriesMVVMCharting_OnClick(object sender, RoutedEventArgs e)
{
View.DataBoundMVVMChart c = new DataBoundMVVMChart();
dockchildren.Children.Clear();
dockchildren.Children.Add(c);
}
}
}
Resource Dictionary:
资源字典:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vw="clr-namespace:WPFTesting12_2.View"
xmlns:vm="clr-namespace:WPFTesting12_2.ViewModel"
>
<DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}">
<vw:DataBoundMVVMChart/>
</DataTemplate>
<Style TargetType="MenuItem">
<Setter Property="Background" Value="Wheat"/>
</Style>
<Style TargetType="Menu">
<Setter Property="Background" Value="Wheat"/>
</Style>
</ResourceDictionary>
View for DataBoundMVVMChart.xaml:
查看 DataBoundMVVMChart.xaml:
<UserControl x:Class="WPFTesting12_2.View.DataBoundMVVMChart"
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:WPFTesting12_2.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary Source="..\Resources.xaml"/>
</UserControl.Resources>
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="TesterContent"/>
</Menu>
<Label DockPanel.Dock="Bottom" Width="300" x:Name="label" Height="50" Foreground="Blue" FontSize="24" Content="{Binding Path=HelloString}"/>
</DockPanel>
</Grid>
</UserControl>
ViewModel to bind to the View above:
ViewModel 绑定到上面的视图:
namespace WPFTesting12_2.ViewModel
{
class DataBoundMVVMChartViewModel : INotifyPropertyChanged
{
private string _HelloString;
public string HelloString
{
get { return _HelloString; }
set
{
_HelloString = value;
RaisePropertyChanged("HelloString");
}
}
public DataBoundMVVMChartViewModel()
{
HelloString = "Hello there from the ViewModel";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
Okay now the binding will fail in the view but yet the resources of the color will come in. So I was thinking I did something wrong but code behind will get the property right away. So let's move on:
好的,现在绑定将在视图中失败,但颜色的资源会进来。所以我想我做错了什么,但后面的代码会立即获得属性。所以让我们继续:
WHAT DID WORK:
什么有效:
Magicially if I just add these four lines to the view:
神奇的是,如果我只是将这四行添加到视图中:
Add this to the declarations in the 'UserControl' segment at top:
将此添加到顶部“UserControl”段中的声明中:
xmlns:local="clr-namespace:WPFTesting12_2.ViewModel"
Then set a reference to the UserControl's DataContext:
然后设置对 UserControl 的 DataContext 的引用:
<UserControl.DataContext>
<local:DataBoundMVVMChartViewModel/>
</UserControl.DataContext>
采纳答案by Rachel
Its important to realize when working with WPF that there are two layers: the data layer (DataContext) and the UI layer (the XAML).
在使用 WPF 时认识到有两层很重要:数据层 ( DataContext) 和 UI 层 (XAML)。
Bindings are used to pull data from the data layer into the View layer.
绑定用于将数据从数据层拉入视图层。
When you write
当你写
<UserControl.DataContext>
<local:DataBoundMVVMChartViewModel/>
</UserControl.DataContext>
You are telling WPF that it should create a new instance of DataBoundMVVMChartViewModeland use it for the data layer of that UserControl.
您告诉 WPF 它应该创建一个新实例DataBoundMVVMChartViewModel并将其用于该 UserControl 的数据层。
When you write
当你写
<Label Content="{Binding HelloString}" />
you are telling the Label to look in its data layer (the DataContext) for a property called "HelloString", and use it for the Contentproperty.
您告诉 Label 在其数据层 (the DataContext) 中查找名为“HelloString”的属性,并将其用于该Content属性。
If the property "HelloString" does not exist in the data layer (which it does not unless you set the DataContextlike you did with <UserControl.DataContext>), the binding will fail and nothing gets displayed except for a binding error in your output window.
如果数据层中不存在属性“HelloString”(它不存在,除非您DataContext像使用 那样设置<UserControl.DataContext>),则绑定将失败并且除了输出窗口中的绑定错误外,不会显示任何内容。
Your DataTemplatefrom your ResourceDictionaryis something different from the DataContext.
Your DataTemplatefrom yourResourceDictionary与DataContext.
In fact, a ResourceDictionaryis just what it sounds like - a dictionary of resources that WPF can use in the application when needed. But objects in the Dictionary are not by default part of the application's UI itself. Instead, they need to be referenced in some way to be used.
事实上,aResourceDictionary就是它听起来的样子——WPF 可以在需要时在应用程序中使用的资源字典。但是字典中的对象默认不是应用程序 UI 本身的一部分。相反,它们需要以某种方式被引用才能使用。
But back to your DataTemplate
但是回到你的 DataTemplate
<DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}">
<vw:DataBoundMVVMChart/>
</DataTemplate>
WPF uses DataTemplates to know how to draw specific types of objects. In your case, this DataTemplateis telling WPF that anytime it needs to draw an object of type DataBoundMVVMChartViewModel, it should do so by using a DataBoundMVVMChart.
WPF 使用 DataTemplates 来了解如何绘制特定类型的对象。在您的情况下,这DataTemplate告诉 WPF,无论何时需要绘制类型为 的对象DataBoundMVVMChartViewModel,都应该使用DataBoundMVVMChart.
To insert an object into the UI, a Contentproperty is normally used, such as
要将一个对象插入到 UI 中,Content通常会使用一个属性,例如
MyLabel.Content = new DataBoundMVVMChartViewModel();
or
或者
<ContentControl Content="{Binding SomeDataboundChartViewModelProperty}" />
I actually started out learning MVVM with the exact same articleyou linked in your question, and had a lot of trouble figuring it out as well, which lead me to doing a little blogging about WPF/MVVM aimed specifically for beginners like me :)
我实际上是从你在问题中链接的完全相同的文章开始学习 MVVM 的,并且在弄清楚它时也遇到了很多麻烦,这导致我写了一篇关于 WPF/MVVM 的博客,专门针对像我这样的初学者:)
If you're interested, I have a few blog articles about WPF/MVVM that may help you understand the technology better.
如果您有兴趣,我有一些关于 WPF/MVVM 的博客文章,可以帮助您更好地理解该技术。
As for your actual question:
至于你的实际问题:
Preferred method for binding in MVVM, Data Template in Resources file or just DataContext in View itself?
在 MVVM 中绑定的首选方法、资源文件中的数据模板还是视图本身中的 DataContext?
I prefer using a DataTemplatein the .Resourcessomewhere, as then your UI is not specifically tied with one specific DataContext.
我更喜欢DataTemplate在.Resources某处使用 a ,因为这样您的 UI 就不会与特定的DataContext.
This is especially important when creating re-usable controls with MVVM. For example, if you have a CalculatorUserControl, and you assigned it a DataContextin the control itself such as with <UserControl.DataContext>, then you could never use that CalculatorUserControlwith any other DataContextother than the one that is created when the control is created.
这在使用 MVVM 创建可重用控件时尤为重要。例如,如果您有一个CalculatorUserControl,并且您DataContext在控件本身中为它分配了一个,例如 with <UserControl.DataContext>,那么除了在创建控件时创建的那个之外,您永远不能将它CalculatorUserControl与任何其他人一起使用DataContext。
So typically I set the DataContextfor the entire application once at startup, and use DataTemplatesto tell WPF how to draw the different ViewModelsor Modelsin my application.
所以通常我DataContext在启动时为整个应用程序设置一次,并用于DataTemplates告诉 WPF 如何绘制不同的ViewModels或Models在我的应用程序中。
My entire application exists in the data layer, and the XAML is merely a user-friendly interface to interact with the data layer. (If you want to see a code sample, check out my Simple MVVM Examplepost)
我的整个应用程序都存在于数据层中,而 XAML 只是一个与数据层交互的用户友好界面。(如果您想查看代码示例,请查看我的Simple MVVM Example帖子)
回答by H.B.
If you want to use implicit DataTemplatesyou have to use the view-model-firstapproach, you however add a viewto your DockPanelwithout a view-model as its context. If you simply add the respective view-model (to a ContentControlor ItemsControl), the view will be created automatically from the DataTemplatewith the view-model as its DataContext.
如果你想使用隐式,DataTemplates你必须使用视图模型优先的方法,但是你可以在没有视图模型的情况下添加一个视图DockPanel作为它的上下文。如果您简单地添加相应的视图模型(到 aContentControl或ItemsControl),视图将自动从DataTemplate以视图模型作为其DataContext.
e.g.
例如
<ItemsControl Name="ic"/>
ic.Items.Add(new DataBoundMVVMChartViewModel());
I personally prefer this over view-first(e.g. adding a view which then assigns its own DataContext), because you usually want references to the view-models, the view is only secondary and manipulated indirectly by interacting with the view-model.
我个人更喜欢这个而不是视图优先(例如添加一个视图,然后分配它自己的视图DataContext),因为您通常需要对视图模型的引用,视图只是次要的,并且通过与视图模型交互间接操作。

