WPF Binding View as Content

落花浮王杯 提交于 2020-01-04 09:23:12

问题


I'm experimenting with some code where I need to mix programmatically created controls with controls defined in XAML.

Can someone explain why when I bind to the Elements View property, the property's 'get' is called twice, yet when binding to the Template property it gets called only once (as expected).

Example output when binding to View :

StringElement
StringElement
BoolElement
BoolElement
StringElement
StringElement

Example output when binding to Template :

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:


Read this from Microsoft: Problem binding image - property called twice for each item

Posted by Microsoft on 4/28/2010 at 10:10 AM This is not a bug. WPF (or any other code) can call your property-getter at any time for any reason; there's no rule that it will be called only once. WPF (and other callers) expects that your property follows the .Net guidelines; in particular that the property-getter is fast, and that it will return the same value from call to call unless you've raised a property-changed notification.

Since you're curious, the reason for the extra call is that WPF 4.0 does some extra work when the property value is a DependencyObject, checking to see whether it can raise "sub-property" change notifications (Freezables are the chief example). This work must be done while setting up the binding path, before doing the first transfer. We could have twisted the code in knots to avoid an extra fetch, but fetches are cheap.

Basically you can't rely the getter for a DependencyObject to be called exactly once.



来源:https://stackoverflow.com/questions/24542773/wpf-binding-view-as-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!