Представление привязки WPF как содержимого

#c# #wpf #templates #binding #contentpresenter

#c# #wpf #шаблоны #привязка #contentpresenter

Вопрос:

Я экспериментирую с некоторым кодом, где мне нужно смешивать программно созданные элементы управления с элементами управления, определенными в XAML.

Кто-нибудь может объяснить, почему, когда я привязываюсь к свойству просмотра элементов, ‘get’ свойства вызывается дважды, но при привязке к свойству шаблона оно вызывается только один раз (как и ожидалось).

Пример вывода при привязке к представлению :

 StringElement
StringElement
BoolElement
BoolElement
StringElement
StringElement
  

Пример вывода при привязке к шаблону :

 StringElement
BoolElement
StringElement
  

 <Window x:Class="BindView.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" WindowStartupLocation="CenterScreen">
<ItemsControl ItemsSource="{Binding Elements}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding View}" />
        </DataTemplate>
        <!--<DataTemplate>
            <ContentPresenter ContentTemplate="{Binding Template}" />
        </DataTemplate>-->
    </ItemsControl.ItemTemplate>
</ItemsControl>
  

 public abstract class Element
{
    public DataTemplate Template
    {
        get
        {
            Console.WriteLine(GetType().Name);
            return OnGetTemplate();
        }
    }

    public abstract DataTemplate OnGetTemplate();

    public UIElement View 
    { 
        get 
        {
            Console.WriteLine(GetType().Name);
            return OnGetView(); 
        } 
    }

    public abstract UIElement OnGetView();

    protected DataTemplate CreateTemplate(Type viewType)
    {
        var xaml = string.Format("<DataTemplate><{0} /></DataTemplate>", viewType.Name);
        var context = new ParserContext();

        context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
        context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
        context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

        return (DataTemplate)XamlReader.Parse(xaml, context);
    }
}

public class StringElement : Element
{
    public override DataTemplate OnGetTemplate() { return CreateTemplate(typeof(TextBox)); }
    public override UIElement OnGetView() { return new TextBox(); }
}

public class BoolElement : Element
{
    public override DataTemplate OnGetTemplate() { return CreateTemplate(typeof(CheckBox)); }
    public override UIElement OnGetView() { return new CheckBox(); }
}

public partial class MainWindow : Window
{
    public List<Element> Elements { get; private set; }

    public MainWindow()
    {
        Elements = new List<Element>() { new StringElement(), new BoolElement(), new StringElement() };
        DataContext = this;
        InitializeComponent();
    }
}
  

Ответ №1:

Прочитайте это от Microsoft: Проблема с привязкой изображения — свойство вызывается дважды для каждого элемента

Опубликовано Microsoft 28.04.2010 в 10: 10 утра, это не ошибка. WPF (или любой другой код) может вызвать ваше средство получения свойств в любое время по любой причине; нет правила, согласно которому оно будет вызвано только один раз. WPF (и другие вызывающие) ожидает, что ваше свойство следует за .Сетевые рекомендации; в частности, что средство получения свойств работает быстро и что оно будет возвращать одно и то же значение от вызова к вызову, если вы не отправили уведомление об изменении свойства.

Поскольку вам интересно, причина дополнительного вызова заключается в том, что WPF 4.0 выполняет некоторую дополнительную работу, когда значением свойства является DependencyObject , проверяя, может ли оно вызывать уведомления об изменении «вложенного свойства» (Freezables — главный пример). Эта работа должна быть выполнена при настройке пути привязки, перед выполнением первой передачи. Мы могли бы скрутить код в узлы, чтобы избежать дополнительной выборки, но выборки дешевы.

В принципе, вы не можете полагаться на средство получения для вызова DependencyObject ровно один раз.