wpf 在代码中设置 DataContext 而不是 XAML 有什么好处?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/862829/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:26:02  来源:igfitidea点击:

What is the advantage of setting DataContext in code instead of XAML?

wpfxamldata-bindingexpression-blenddatacontext

提问by Edward Tanguay

There seem to be two main ways to define DataContext in WPF:

在 WPF 中定义 DataContext 似乎有两种主要方法:

  • either in codelike this:
  • 或者在这样的代码中

App.xaml.cs (taken from the WPF MVVM Toolkit template):

App.xaml.cs(取自WPF MVVM 工具包模板):

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
        // Create the ViewModel and expose it using the View's DataContext
        MainView mainView = new MainView();
        MainViewModel mainViewModel = new MainViewModel();
        mainViewModel.LoadCustomers("c:\testdata2\Customers.xml");
        mainView.DataContext = mainViewModel;
        mainView.Show();
    }
}
  • or in XAMLlike this:
  • 或者像这样在 XAML 中

Window1.xaml:

Window1.xaml:

<DockPanel>
    <StackPanel
        HorizontalAlignment="Left"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <StackPanel.DataContext>
            <local:CustomerViewModel />
        </StackPanel.DataContext>
        <TextBlock Text="{Binding Path=FirstName}" />
        <TextBlock Text=" " />
        <TextBlock Text="{Binding Path=LastName}" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <ListBox ItemsSource="{Binding Source={StaticResource FileNames}}" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <ComboBox
            ItemsSource="{Binding Source={StaticResource Directories}}"
            SelectedIndex="0" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <StackPanel.DataContext>
            <local:SystemInformationViewModel />
        </StackPanel.DataContext>
        <TextBlock Text="{Binding Path=CurrentTime}" />
    </StackPanel>
</DockPanel>

One advantage that defining the DataContext in XAML has is that your data shows up in Expression Blend design modeand Expression Blend allows you to do quite a lot within the GUI e.g. choose fields from your datasource, etc. as shown here.

在 XAML 中定义 DataContext 的一个优点是您的数据显示在 Expression Blend 设计模式中,并且 Expression Blend 允许您在 GUI 中执行很多操作,例如从您的数据源中选择字段等,如此处所示

I have read that binding ADO.NET objects cannot be bound in XAML(although I don't see why you could write a minimal wrapper for them to which you could bind from XAML).

我读过绑定ADO.NET 对象不能在 XAML 中绑定(尽管我不明白为什么你可以为它们编写一个可以从 XAML 绑定到的最小包装器)。

Strange that the WPF Team in making the WPF MVVM templates define the DataContext in codewhich very quickly makes it impracticable to edit your Views in Expression Blend, since your data doesn't show up in design mode which is often a significant part of the layout.

奇怪的是,WPF 团队在制作 WPF MVVM 模板时在代码中定义了 DataContext,这很快使得在 Expression Blend 中编辑您的视图变得不切实际,因为您的数据不会显示在设计模式中,而设计模式通常是布局的重要组成部分.

So I'm thinking there must be some advantagedown the road to setting the DataContext in code instead of XAML, anyone know what it is?

所以我认为在代码中而不是 XAML 中设置 DataContext一定有一些优势,有人知道它是什么吗?

回答by Simon_Weaver

You can (maybe in 2009 you couldn't) get the best of both worlds by using the d:DataContextattribute. You don't need any of that ViewModelLocatorcrazinessif you're not ready for that yet :-)

您可以(也许在 2009 年您不能)通过使用该d:DataContext属性来两全其美。如果你还没有准备好,你不需要任何那种ViewModelLocator疯狂:-)

First make sure that you have the following XML namespace defined in your root element:

首先确保在根元素中定义了以下 XML 命名空间:

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

Then you can add the following attribute to an element in your xaml:

然后,您可以将以下属性添加到 xaml 中的元素:

d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type=vm:CustomerInsightViewModel}"

d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type=vm:CustomerInsightViewModel}"

In your xaml codebehind :

在您的 xaml 代码隐藏中:

    public CustomerInsightUserControl()
    {
        InitializeComponent();

        if (!DesignerProperties.IsInDesignTool)
        {
            DataContext = new CustomerInsightViewModel();
        }
    }

Then in your ViewModel:

然后在您的 ViewModel 中:

    public CustomerInsightViewModel()
    {
        if (IsInDesignMode)
        {
            // Create design time data
            Customer = new Customer() {
                FirstName=... 
            }
        }
        else {
            // Create datacontext and load customers
        }
    }

Don't miss the IsDesignTimeCreatable=Trueor else Blend won't instantiate your class

不要错过IsDesignTimeCreatable=True否则 Blend 不会实例化您的类

回答by HakonB

I don't like the idea of having Expression Blend try to instantiate my data objects.

我不喜欢让 Expression Blend 尝试实例化我的数据对象的想法。

I set the DataContext through code where I am able to use Dependency Injection to inject the proper objects, services, providers or what else I am using to find my code.

我通过代码设置 DataContext,我可以在其中使用依赖注入来注入正确的对象、服务、提供程序或我用来查找代码的其他内容。

回答by Denis Troller

There could be a kind of solution to this, using the DataObjectProvider to mask the fact that the data is instantiated outside of XAML.

可能有一种解决方案,使用 DataObjectProvider 来掩盖数据是在 XAML 之外实例化的事实。

It will state what the type of the DataContext is, which should be enough for Blend to pick up the properties.

它将说明 DataContext 的类型是什么,这应该足以让 Blend 获取属性。

I have not tried this yet, so take it with a grain of salt, but it is certainly worth investigating.

我还没有尝试过,所以请谨慎对待,但这当然值得研究。

回答by Dave

See Rob's article about design time data in Blend: http://www.robfe.com/2009/08/design-time-data-in-expression-blend-3/

请参阅 Rob 关于 Blend 中设计时数据的文章:http: //www.robfe.com/2009/08/design-time-data-in-expression-blend-3/

回答by Ali Shafai

Having it in codebehind makes it easy to inject the datacontext using unity.

在代码隐藏中使用它可以很容易地使用 unity 注入数据上下文。

回答by George

It should also be possible to use ObjectDataProvider to establish an object factory using Unity or other IOCs as implied here...

也应该可以使用 ObjectDataProvider 来使用 Unity 或其他 IOC 建立对象工厂,如此处暗示的那样......

http://social.msdn.microsoft.com/Forums/en/wpf/thread/1ff9e90e-302e-436e-bab3-ca4bad2b85af

http://social.msdn.microsoft.com/Forums/en/wpf/thread/1ff9e90e-302e-436e-bab3-ca4bad2b85af

in particular...

特别是...

http://www.codeproject.com/Articles/43806/WPF-Ninject-Dojo-The-Data-Provider.aspx

http://www.codeproject.com/Articles/43806/WPF-Ninject-Dojo-The-Data-Provider.aspx

回答by George

In my experience, it is best to design an interface layout against at least a sample of the data it will present. To do otherwise is to be blind to cheap insights and expensive oversights.

根据我的经验,最好至少针对它将呈现的数据样本设计界面布局。否则就是对廉价的见解和昂贵的疏忽视而不见。