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


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

Может кто-нибудь объяснить, почему при привязке к свойству Elements View свойство " get " вызывается дважды, но при привязке к свойству Template оно вызывается только один раз (как и ожидалось).

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

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 2

1 ответ:

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

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

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

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