Qeustion:
在设置了PropertyDescriptor之后,是否有可能向ICustomTypeDescriptor的PropertyDescriptorCollection中添加一个附加的DataConext?
详细信息:
我正在创建一个实现ICustomTypeDescriptor的新类,其目标是在运行时动态地向该类添加新属性,并将它们绑定到WPF应用程序。
例如,用户可以通过脚本语言定义一个新属性(例如。在应用程序运行时,我希望XAML能够绑定到该属性。
我遇到的问题是,如果在设置了DataContext之后添加了一个属性,到XAML的绑定就不能工作;它不会尝试调用关联的PropertyDescriptor.GetValue方法。
我相信这个问题是,在将DataContext设置为我的ICustomTypeDescriptor后不久,它的ICustomTypeDescriptor.GetProperties实现就被调用了,此时我为所有已知的属性创建了PropertyDescriptor。然后,我随后添加了新的属性,但是没有能力为它们添加新的PropertyDescriptor。
代码:
我在这里删减了一些代码,以使它更容易阅读,删除了大量的锅炉板的东西。
本例中的思想是,第一个文本字段绑定到动态创建的属性,该属性是在构造期间定义的,而第二个文本字段绑定到一个在单击Button之前不存在的属性。
单击按钮时创建的属性只有在我将DataBound设置为新的东西时才能正确地获取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;
}
}
<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>
发布于 2014-01-21 02:03:12
我不完全理解你的问题。但是,我想,在绑定表达式中使用字典可能是问题的一部分。在我看来,将在xaml中绑定的集合应该是从ObservableCollection中删除的类型,以便拥有在集合更改时通知视图的能力。
https://stackoverflow.com/questions/21246731
复制相似问题