#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 ровно один раз.