В чем преимущество настройки DataContext в коде вместо XAML?

Кажется, существуют два основных способа определения DataContext в WPF:

  • либо в коде, как это:

App.xaml.cs(взято из WPF MVVM Toolkit template):

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
        // Create the ViewModel and expose it using the View DataContext
        MainView mainView = new MainView();
        MainViewModel mainViewModel = new MainViewModel();
        mainViewModel.LoadCustomers("c:\\testdata2\\Customers.xml");
        mainView.DataContext = mainViewModel;
        mainView.Show();
    }
}
  • или в 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>

Одно из преимуществ, заключающееся в том, что определение DataContext в XAML состоит в том, что ваши данные отображаются в режиме разработки Expression Blend, а Expression Blend позволяет делать довольно много в графическом интерфейсе, например. выберите поля из источника данных и т.д. как показано здесь.

Я прочитал, что привязка объектов ADO.NET не может быть привязана к XAML (хотя я не понимаю, почему вы могли бы написать минимальную оболочку для них, с которой вы могли бы связываться с XAML).

Странно, что команда WPF при создании шаблонов MVVM WPF определяет DataContext в коде, что очень быстро делает невозможным редактировать ваши представления в Expression Blend, поскольку ваши данные не отображаются в дизайне режим, который часто является значительной частью макета.

Итак, я думаю, что должно быть какое-то преимущество по пути к установке DataContext в коде вместо XAML, кто-нибудь знает, что это такое?

Ответы

Ответ 1

Вы можете (возможно, в 2009 году вы не смогли) получить лучшее из обоих миров, используя атрибут d:DataContext. Вам не нужен какой-либо из ViewModelLocator craziness, если вы еще не готовы к этому: -)

Сначала убедитесь, что в корневом элементе указано следующее пространство имен XML:

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

Затем вы можете добавить следующий атрибут к элементу в вашем xaml:

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

В вашем xaml codebehind:

    public CustomerInsightUserControl()
    {
        InitializeComponent();

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

Затем в вашей ViewModel:

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

Не пропустите IsDesignTimeCreatable=True, иначе Blend не будет создавать экземпляр класса

Ответ 2

Мне не нравится идея использования Expression Blend для создания экземпляров объектов данных.

Я устанавливаю DataContext через код, где я могу использовать Dependency Injection для инъекции правильных объектов, служб, поставщиков или того, что еще я использую, чтобы найти свой код.

Ответ 3

Наличие в коде позволяет легко вводить datacontext, используя единство.

Ответ 4

Это может быть какое-то решение, используя DataObjectProvider для маскирования того факта, что данные создаются вне XAML.

Он укажет, что такое тип DataContext, которого должно быть достаточно, чтобы Blend мог получить свойства.

Я еще не пробовал этого, поэтому возьмите его с солью, но это, безусловно, стоит исследовать.

Ответ 7

По моему опыту, лучше всего разработать макет интерфейса по меньшей мере по образцу данных, которые он будет представлять. Сделать иначе - значит быть слепым к дешевым идеям и дорогим оплошностям.