Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.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# 如何在设置DataContext后向ICustomTypeDescriptor添加其他PropertyDescriptor_C#_Wpf_Xaml_Data Binding - Fatal编程技术网

C# 如何在设置DataContext后向ICustomTypeDescriptor添加其他PropertyDescriptor

C# 如何在设置DataContext后向ICustomTypeDescriptor添加其他PropertyDescriptor,c#,wpf,xaml,data-binding,C#,Wpf,Xaml,Data Binding,Qeustion: 在设置了DataConext之后,是否可以在ICustomTypeDescriptor的PropertyDescriptorCollection中添加额外的PropertyDescriptor 详细信息: 我正在创建一个新类,该类实现了ICustomTypeDescriptor,目标是在运行时向该类动态添加新属性,并将它们绑定到WPF应用程序 例如,用户可以在应用程序运行时通过脚本语言(如Lua)定义新属性,我希望XAML能够绑定到该属性 我遇到的问题是,如果我在设置Data

Qeustion:

在设置了
DataConext
之后,是否可以在
ICustomTypeDescriptor
PropertyDescriptorCollection
中添加额外的
PropertyDescriptor

详细信息:

我正在创建一个新类,该类实现了
ICustomTypeDescriptor
,目标是在运行时向该类动态添加新属性,并将它们绑定到WPF应用程序

例如,用户可以在应用程序运行时通过脚本语言(如Lua)定义新属性,我希望XAML能够绑定到该属性

我遇到的问题是,如果我在设置DataContext之后添加属性,那么到XAML的绑定将无法工作;它不会尝试调用关联的
PropertyDescriptor.GetValue
方法

我认为这个问题是,在将DataContext设置为我的
ICustomTypeDescriptor
后不久,它的
ICustomTypeDescriptor.GetProperties
的实现被调用,此时我为所有已知属性创建了
PropertyDescriptor
。随后我添加了新属性,但无法为它们添加新的
PropertyDescriptor

代码:

我在这里对代码进行了一些精简,以使其更易于阅读,删除了许多锅炉板的内容

本例中的想法是,第一个文本字段绑定到一个动态创建的属性,该属性是在构造期间定义的,第二个文本字段绑定到一个在单击按钮之前不存在的属性

单击按钮时创建的属性只有在我将DataContext设置为新内容时才能正确绑定数据

public class MyCustomType : ICustomTypeDescriptor, INotifyPropertyChanged
{
    Dictionary<string, object> Properties = new Dictionary<string, object>();

    public event PropertyChangedEventHandler PropertyChanged;

    public MyCustomType()
    {
        Properties.Add("CustomProp", "What up, world?");
    }

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public void CreateOrSetProperty(string name, object val)
    {
        Properties[name] = val;
        NotifyPropertyChanged(name);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        List<PropertyDescriptor> props = new List<PropertyDescriptor>();

        foreach (KeyValuePair<string, object> entry in Properties)
        {
            props.Add(new MyCustomTypePropertyDescriptor(entry.Key, attributes));
        }

        return new PropertyDescriptorCollection(props.ToArray());
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return ((ICustomTypeDescriptor)this).GetProperties(null);
    }

    class MyCustomTypePropertyDescriptor : PropertyDescriptor
    {
        public MyCustomTypePropertyDescriptor(string name, Attribute[] attrs)
            : base(name, attrs)
        {
        }

        public override object GetValue(object component)
        {
            return ((MyCustomType)component).Properties[Name];
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

         public override void SetValue(object component, object value)
        {
            ((MyCustomType)component).Properties[Name] = value;
        }
    }
}

public partial class Page5
{
    public Page5()
    {
        this.InitializeComponent();
    }

    private void BtnAddProperty_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        // A static resource defined in XAML used as the DataContext for both text blocks.
        MyCustomType c = Resources["MyCustomTypeData"] as MyCustomType;

        // Create a new property which is already being referenced in a DataBind in XAML but 
        // prior to this function being called, did not exist.
        c.CreateOrSetProperty("AnotherProp", "Another Property!");

        // If I clear the DataContext and set it back to the previous value it triggers 
        // ICustomTypeDescriptor.GetProperties to get called again, and the property gets
        // Bound. If I don't do this, it fails.
        //MyTextBlock2.DataContext = null;
        //MyTextBlock2.DataContext = c;
    }
}
公共类MyCustomType:ICustomTypeDescriptor,INotifyPropertyChanged
{
字典属性=新字典();
公共事件属性更改事件处理程序属性更改;
公共MyCustomType()
{
添加(“CustomProp”、“What up,world?”);
}
私有void NotifyPropertyChanged(字符串信息)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(信息));
}
}
public void CreateOrSetProperty(字符串名称,对象值)
{
属性[名称]=val;
NotifyPropertyChanged(名称);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(属性[]属性)
{
列表道具=新列表();
foreach(属性中的KeyValuePair条目)
{
添加(新的MyCustomTypePropertyDescriptor(entry.Key,attributes));
}
返回新的PropertyDescriptorCollection(props.ToArray());
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
返回((ICustomTypeDescriptor)this.GetProperties(null);
}
类MyCustomTypePropertyDescriptor:PropertyDescriptor
{
公共MyCustomTypePropertyDescriptor(字符串名称,属性[]属性)
:base(名称、属性)
{
}
公共覆盖对象GetValue(对象组件)
{
返回((MyCustomType)组件)。属性[名称];
}
公共覆盖布尔为只读
{
获取{return false;}
}
公共覆盖无效设置值(对象组件、对象值)
{
((MyCustomType)组件)。属性[名称]=值;
}
}
}
公共部分类第5页
{
公共网页5(
{
this.InitializeComponent();
}
私有无效BtnAddProperty_单击(对象发送者,System.Windows.RoutedEventArgs e)
{
//XAML中定义的静态资源,用作两个文本块的DataContext。
MyCustomType c=资源[“MyCustomTypeData”]作为MyCustomType;
//创建已在XAML中的数据绑定中引用的新属性,但
//在调用此函数之前,不存在。
c、 CreateOrSetProperty(“另一个属性”,“另一个属性!”);
//如果我清除DataContext并将其设置回它触发的前一个值
//ICustomTypeDescriptor.GetProperties再次调用,并且该属性
//当然。如果我不这样做,它就失败了。
//MyTextBlock2.DataContext=null;
//MyTextBlock2.DataContext=c;
}
}



我不完全理解你的问题。然而,我想在绑定表达式中使用字典可能是您的问题的一部分。在我看来,将在xaml中绑定的集合应该是从ObservableCollection派生的类型,以便拥有在集合更改时通知视图的能力。

我正在通过ICustomTypeDescriptor的实例进行绑定,并编写自定义PropertyDescriptor。我认为这本词典应该是无关紧要的。这正是我选择存储属性数据的方式。
<Page.Resources>
    <WpfApplication1:MyCustomType x:Key="MyCustomTypeData"/>
</Page.Resources>

<Grid x:Name="LayoutRoot">
    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <TextBlock DataContext="{StaticResource MyCustomTypeData}" x:Name="MyTextBlock" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding CustomProp}" VerticalAlignment="Top" FontSize="32" Background="Black" Foreground="White"/>
        <TextBlock DataContext="{StaticResource MyCustomTypeData}" x:Name="MyTextBlock2" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding AnotherProp}" VerticalAlignment="Top" FontSize="32" Background="Black" Foreground="White"/>
        <Button x:Name="BtnAddProperty" Content="Add Additional Property" Click="BtnAddProperty_Click"/>
    </StackPanel>
</Grid>