MVVM中绑定的首选方法,资源文件中的数据模板或View中的DataContext? [英] Preferred method for binding in MVVM, Data Template in Resources file or just DataContext in View itself?

查看:135
本文介绍了MVVM中绑定的首选方法,资源文件中的数据模板或View中的DataContext?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个我已经让我失望了,因为我看着一切,但是我一定是想念一些东西。我已经从MSDN杂志中删除了传统的MVVM模式:



http://msdn.microsoft.com/en-us/magazine/dd419663.aspx



同时学习MVVM。然而,我通常会复制大部分的代码,然后替换它,因为我需要,但今天我想从头开始构建一些东西,看到可能比我想象的更多。当我使用资源字典时,MVVM似乎无法使用绑定,而是直接使用数据标签。这个问题最终要找到其他开发者建议使用绑定他们找到的。



问题的总结是这样的:为什么资源字典中的DataTemplate看起来不会显示在下面,但直接的DataContext方法与请立即查看绑定?



是因为我在代码背后的设置视图中混合了代码。或者潜在地因为别的东西。如果我在View的XAML中直接设置了DataContext,那么在viewmodel中看起来我的属性和它的实现设置正确,但为什么不在资源字典中?我认为这种方法的优点是您可以一次性设置一堆关系。如果有其他一些设置需要做,让我好奇,让它上班。在使用数据模板的MVVM方法的主要示例中,它是好奇的,但是似乎有更多的设置它们比我正在做,以使他们的绑定工作。



我没有为我工作:



我试图做一些在主窗口xaml中的基本东西,留下我的一些代码,使其更简单:



主窗口XAML:

 < Window xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://
xmlns:dxc =http://schemas.devexpress.com/winfx/2008/xaml/chartsx:Class =WPFTesting12_2.MainWindow
Title =MainWindowHeight =350Width =525>
< Window.Resources>
< ResourceDictionary Source =Resources.xaml/>
< /Window.Resources>
< Grid>
< DockPanel x:Name =dockpanel>
< Menu DockPanel.Dock =TopHeight =30>
< MenuItem Header =Charting>
< MenuItem Header =MVVMDataBoundx:Name =mnuDataBoundSeriesMVVMChartingClick =mnuDataBoundSeriesMVVMCharting_OnClick/>
< / MenuItem>
< / Menu>
< TextBlock Height =5Background =BlackDockPanel.Dock =Top/>
< DockPanel x:Name =dockchildrenDockPanel.Dock =Bottom/>
< / DockPanel>
< / Grid>
< / Window>

主窗口代码背后:

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

资源字典:

 < 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 =BackgroundValue =Wheat/>
< / Style>
< Style TargetType =Menu>
< Setter Property =BackgroundValue =Wheat/>
< / Style>

< / ResourceDictionary>

查看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 =300d:DesignWidth =300>
< UserControl.Resources>
< ResourceDictionary Source =.. \Resources.xaml/>
< /UserControl.Resources>
< Grid>
& DockPanel>
< Menu DockPanel.Dock =Top>
< MenuItem Header =TesterContent/>
< / Menu>
< Label DockPanel.Dock =BottomWidth =300x:Name =labelHeight =50Foreground =BlueFontSize =24Content ={Binding Path = HelloString} />
< / DockPanel>
< / Grid>
< / UserControl>

ViewModel绑定到上面的视图:

 命名空间WPFTesting12_2.ViewModel 
{
class DataBoundMVVMChartViewModel:INotifyPropertyChanged
{
private string _HelloString;

public string HelloString
{
get {return _HelloString; }
set
{
_HelloString = value;
RaisePropertyChanged(HelloString);
}
}

public DataBoundMVVMChartViewModel()
{
HelloString =来自ViewModel的Hello
}

public event PropertyChangedEventHandler PropertyChanged;

protected void RaisePropertyChanged(string propertyName)
{
if(PropertyChanged!= null)
PropertyChanged(this,new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}

现在绑定将失败在视图中,但是颜色的资源会进来。所以我在想我做错了,但后面的代码会立即获得该属性。所以我们继续下去:



什么工作:



将这四行添加到视图中:



将此添加到顶部UserControl段中的声明:

  xmlns:local =clr-namespace:WPFTesting12_2.ViewModel

然后设置对UserControl的DataContext的引用:

 < UserControl.DataContext> 
< local:DataBoundMVVMChartViewModel />
< /UserControl.DataContext>


解决方案

在使用WPF时,两层:数据层( DataContext )和UI层(XAML)。



绑定用于将数据从数据层拉入View层。



当您写入

 < UserControl.DataContext> 
< local:DataBoundMVVMChartViewModel />
< /UserControl.DataContext>

您正在告诉WPF应该创建一个新的实例DataBoundMVVMChartViewModel 并将其用于该UserControl的数据层。



当您写

 < Label Content ={Binding HelloString}/>你要告诉Label看它的数据层( DataContext  


),用于名为HelloString的属性,并将其用于内容属性。



如果属性HelloString不存在于数据层中(除非您设置了 DataContext ,就像您使用< UserControl .DataContext> ),绑定将失败,除了输出窗口中的绑定错误之外,不会显示任何内容。



您的 DataTemplate ResourceDictionary DataContext 不同。



事实上,一个 ResourceDictionary 就是这样 - WPF可以使用的资源字典需要时应用但是Dictionary中的对象不是应用程序UI本身的默认部分。相反,他们需要以某种方式引用才能使用。



但是回到你的 DataTemplate

 < DataTemplate DataType ={x:Type vm:DataBoundMVVMChartViewModel}> 
< vw:DataBoundMVVMChart />
< / DataTemplate>

WPF使用DataTemplates来了解如何绘制特定类型的对象。在你的情况下,这个 DataTemplate 告诉WPF,任何时候需要绘制一个类型为 DataBoundMVVMChartViewModel 的对象,它应该所以通过使用 DataBoundMVVMChart



要将对象插入UI,通常使用内容属性,例如

  MyLabel.Content = new DataBoundMVVMChartViewModel(); 

 < ContentControl Content ={Binding SomeDataboundChartViewModelProperty}/>我实际上开始学习使用完全相同的粒子,您在问题中链接,并且遇到了很多麻烦它也是,这导致我做一个关于WPF / MVVM的一个博客,专门针对像我这样的初学者:)



如果你有兴趣,我有几个关于WPF / MVVM的博客文章可能有助于您更好地了解技术。





对于您的实际问题:


MVVM中绑定的首选方法,资源文件中的数据模板或只有DataContext在View本身?


我更喜欢使用 DataTemplate code> .Resources 在某处,因为您的UI不是特定的绑定在一个特定的 DataContext



当使用MVVM创建可重用的控件时,这一点尤为重要。例如,如果您有一个 CalculatorUserControl ,并且您在控件本身中分配了一个 DataContext ,例如使用< UserControl.DataContext> ,那么你永远不能使用这个 CalculatorUserControl 与任何其他 DataContext 创建控件之前创建的code



所以通常我设置 DataContext 对于整个应用程序一次启动,并使用 DataTemplates 告诉WPF如何绘制不同的 ViewModels 模型在我的应用程序。



我的整个应用程序都存在于数据层中,XAML只是一个用户友好的界面来与数据层进行交互。 (如果您想查看代码示例,请查看我的简单MVVM示例帖子)


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:

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.

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?

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.

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:

Main Window 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:

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

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:

xmlns:local="clr-namespace:WPFTesting12_2.ViewModel"

Then set a reference to the UserControl's DataContext:

<UserControl.DataContext>
        <local:DataBoundMVVMChartViewModel/>
    </UserControl.DataContext>

解决方案

Its important to realize when working with WPF that there are two layers: the data layer (DataContext) and the UI layer (the 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 DataBoundMVVMChartViewModel and use it for the data layer of that 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 Content property.

If the property "HelloString" does not exist in the data layer (which it does not unless you set the DataContext like you did with <UserControl.DataContext>), the binding will fail and nothing gets displayed except for a binding error in your output window.

Your DataTemplate from your ResourceDictionary is something different from the DataContext.

In fact, a ResourceDictionary is 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.

But back to your 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 DataTemplate is telling WPF that anytime it needs to draw an object of type DataBoundMVVMChartViewModel, it should do so by using a DataBoundMVVMChart.

To insert an object into the UI, a Content property is normally used, such as

MyLabel.Content = new DataBoundMVVMChartViewModel();

or

<ContentControl Content="{Binding SomeDataboundChartViewModelProperty}" />

I actually started out learning MVVM with the exact same article you 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 :)

If you're interested, I have a few blog articles about WPF/MVVM that may help you understand the technology better.

As for your actual question:

Preferred method for binding in MVVM, Data Template in Resources file or just DataContext in View itself?

I prefer using a DataTemplate in the .Resources somewhere, as then your UI is not specifically tied with one specific DataContext.

This is especially important when creating re-usable controls with MVVM. For example, if you have a CalculatorUserControl, and you assigned it a DataContext in the control itself such as with <UserControl.DataContext>, then you could never use that CalculatorUserControl with any other DataContext other than the one that is created when the control is created.

So typically I set the DataContext for the entire application once at startup, and use DataTemplates to tell WPF how to draw the different ViewModels or Models in my application.

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 Example post)

这篇关于MVVM中绑定的首选方法,资源文件中的数据模板或View中的DataContext?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆