Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 作为内容的WPF绑定视图_C#_Wpf_Templates_Binding_Contentpresenter - Fatal编程技术网

C# 作为内容的WPF绑定视图

C# 作为内容的WPF绑定视图,c#,wpf,templates,binding,contentpresenter,C#,Wpf,Templates,Binding,Contentpresenter,我正在试验一些代码,其中我需要混合编程创建的控件和XAML中定义的控件 有人能解释为什么当我绑定到Elements View属性时,属性的“get”被调用两次,而当绑定到Template属性时,它只被调用一次(如预期的那样) 绑定到视图时的输出示例: StringElement StringElement BoolElement BoolElement StringElement StringElement 绑定到模板时的输出示例: StringElement BoolElement Stri

我正在试验一些代码,其中我需要混合编程创建的控件和XAML中定义的控件

有人能解释为什么当我绑定到Elements View属性时,属性的“get”被调用两次,而当绑定到Template属性时,它只被调用一次(如预期的那样)

绑定到视图时的输出示例:

StringElement
StringElement
BoolElement
BoolElement
StringElement
StringElement
绑定到模板时的输出示例:

StringElement
BoolElement
StringElement
--


公共抽象类元素
{
公共数据模板
{
得到
{
Console.WriteLine(GetType().Name);
返回OnGetTemplate();
}
}
公共抽象数据模板OnGetTemplate();
公共元素视图
{ 
得到
{
Console.WriteLine(GetType().Name);
返回OnGetView();
} 
}
公共抽象元素UIElement OnGetView();
受保护的DataTemplate CreateTemplate(类型viewType)
{
var xaml=string.Format(“,viewType.Name”);
var context=new ParserContext();
context.XamlTypeMapper=新的XamlTypeMapper(新字符串[0]);
context.xmlnsdirectionary.Add(“,”http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.xmlnsdirectionary.Add(“x”http://schemas.microsoft.com/winfx/2006/xaml");
return(DataTemplate)XamlReader.Parse(xaml,context);
}
}
公共类StringElement:元素
{
公共重写DataTemplate OnGetTemplate(){return CreateTemplate(typeof(TextBox));}
公共重写UIElement OnGetView(){返回新文本框();}
}
公共类booleElement:元素
{
公共重写DataTemplate OnGetTemplate(){返回CreateTemplate(typeof(复选框));}
公共重写UIElement OnGetView(){返回新复选框();}
}
公共部分类主窗口:窗口
{
公共列表元素{get;private set;}
公共主窗口()
{
Elements=new List(){new StringElement(),new BooleElement(),new StringElement()};
DataContext=this;
初始化组件();
}
}

从Microsoft阅读以下内容:

由微软于2010年4月28日上午10:10发布,这不是一个bug。WPF (或任何其他代码)可以随时调用您的属性getter以获取任何 理性;没有规定只调用一次。WPF(和 其他调用方)希望您的属性遵循.Net准则; 特别是属性getter是快速的,并且它将 在调用之间返回相同的值,除非您已引发 属性更改通知

既然您很好奇,那么额外调用的原因是WPF 4.0 当属性值为DependencyObject时,执行一些额外工作, 检查是否可以引发“子属性”更改 通知(Freezable是主要示例)。这项工作一定很重要 在设置绑定路径时完成,然后执行第一步 转移我们本可以把代码扭成一团来避免额外的错误 去拿,但是去拿很便宜

基本上,您不能依赖getter只调用一次DependencyObject

<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();
    }
}