今天我的情况非常艰难。由于缺乏WPF的经验,我无法想象。我从类开发用于GUI生成的小框架(WinForms \ WPF \ HTML)。为此,我需要动态创建元素。
我使用DependencyProperty自定义UserControl
public partial class ObjectPicker : UserControl
{
private ViewModel _vm;
public ObjectPicker()
{
InitializeComponent();
}
public object ObjectValue
{
get { return GetValue(ObjectValueProperty); }
set { SetValue(ObjectValueProperty, value); }
}
public static DependencyProperty ObjectValueProperty =
DependencyProperty.Register(
"ObjectValue",
typeof(object),
typeof(ObjectPicker),
new FrameworkPropertyMetadata(
new PropertyMetadata(new object(), OnObjectChangeNotify, CoerceValueCallback), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
private static void OnObjectChangeNotify(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as ObjectPicker;
sender.OnObjectValueChange(d, e);
}
public void OnObjectValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
this.ObjectValue = e.NewValue;
}
}
我有CustomBoundColumn,我覆盖了GenerateElement方法(其中BindingObject - 包含2个属性Value和PropName的包装器)。然后我像这样绑定对象,然后它不起作用。
var content = new ContentControl();
content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName);
var propName = ((Binding)Binding).Path.Path;
BindingObject bo = new BindingObject(propName, dataItem);
content.SetValue(ContentControl.ContentProperty, bo);
return content;
数据模板(例如我放了另外两个完美的模板):
<DataTemplate x:Key="TextBoxDataTemplate">
<TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
<DataTemplate x:Key="DatePickerDataTemplate">
<DatePicker SelectedDate="{Binding Value,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
<DataTemplate x:Key="ObjectPickerDataTemplate">
<local:ObjectPicker ObjectValue="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
当我以编程方式绑定时:
objectPicker.SetBinding(ObjectPicker.ObjectValueProperty, binding);
什么时候有效。
我不知道解决此问题需要哪些其他信息。如果你需要更多,只需留下评论即可添加。
UPDATE1:添加BindingObject类
public class BindingObject : INotifyPropertyChanged
{
private object _value;
private PropertyDescriptor _pd;
private MethodInfo _method;
public BindingObject(string propName, object value)
{
_method = value.GetType().GetMethods().FirstOrDefault(x => x.Name == "OnPropertyChanged");
if (!(value is INotifyPropertyChanged) || _method == null) throw new Exception("Invalid value");
_value = value;
_pd = TypeDescriptor.GetProperties(_value.GetType())[propName];
(_value as INotifyPropertyChanged).PropertyChanged += (o, e) =>
{
OnPropertyChanged(nameof(Value));
OnPropertyChanged(_pd.Name);
};
}
public string PropName
{
get { return _pd.Name; }
}
public object Value
{
get
{
return _pd.GetValue(_value);
}
set
{
_pd.SetValue(_value, value);
}
}
private void RaisePropertyChanged()
{
_method.Invoke(_value, new[] { nameof(Value) });
_method.Invoke(_value, new[] { _pd.Name });
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
UPDATE2:dataItem的实现示例
public class DataItem
{
public virtual string Value1 { get; set; } // This type of property work fine and binding
public virtual int Value2 { get; set; } // This type of property work fine and binding
public virtual DateTime Value3 { get; set; } // This type of property work fine and binding
public virtual ExampleComplexObject Object { get; set; } // This type not working
}
public class ExampleComplexObject
{
public virtual int Value1 { get; set; }
public virtual string Value2 { get; set; }
}
在运行时,需要创建对象类型传递给工厂,其中使用INotifyPropertyChanged实现从传递类型创建代理对象。
答案 0 :(得分:0)
我不确定我是否理解您的确切问题,但您可以尝试将ContentControl的Content属性设置为数据对象:
var content = new ContentControl();
content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName);
content.SetValue(ContentControl.ContentProperty, dataItem);
return content;
然后,您应该能够使用{Binding Value}
绑定到DataTemplate中的Value属性。