我有一个用于ActiveX WinForms UserControl的WPF UserControl包装器,因此我可以正确使用MVVM / Bindings而无需从视图模型中操作UI。
我的UserControl有一个ItemsSource DependencyProperty(以及其他各种)。我现在想要的是以与ComboBox具有SelectedValuePath
或DisplayMemberPath
属性相同的方式实现“Path”属性,以使其成为独立模块。
目前:
XAML
<myControls:MyUserControl ItemsSource="{Binding ItemsSource}" Title.../>
相关代码隐藏
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(ItemsSourcePropertyName, typeof(IEnumerable), typeof(MyControl), new PropertyMetadata(ItemsSourcePropertyChanged));
public const string ItemsSourcePropertyName = "ItemsSource";
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
private static void ItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyControl control = (MyControl)sender;
if (control != null)
{
control.PropertyChanged();
}
}
private void PropertyChanged()
{
if (ItemsSource is List<MyModel>) //TODO: figure out how to avoid this cast for user input fieldname for the path
{
List<MyModel> list = (List<MyModel>)ItemsSource;
if (m_axHost == null)
{
// Create the interop host control.
m_axHost = new System.Windows.Forms.Integration.WindowsFormsHost();
// Create the ActiveX control.
MyAxControl AXcontrol = new MyAxControl();
AXcontrol.SetData(list.Select(a=>a.XValue).ToArray(), list.Select(a=>a.YValue).ToArray(), Title, ...);
// Assign the ActiveX control as the host control's child.
m_axHost.Child = AXcontrol;
// Add the interop host control to the Grid
// control's collection of child controls.
this.axControlHolder.Children.Add(m_axHost);
}
else
{
MyAxControl AXcontrol = (MyAxControl)m_axHost.Child;
AXcontrol.ClearData();
control.SetData(list.Select(a=>a.XValue).ToArray(), list.Select(a=>a.YValue).ToArray(), Title, ...);
}
}
}
我想:
<myControls:MyUserControl ItemsSource="{Binding ItemsSource}" XValuePath="XPathname" YValuePath="YPathname" Title.../>
和
control.SetData(ItemsSource.Select(a=>a."XPathname").ToArray(), ItemsSource.Select(a=>a."YPathname").ToArray(), Title, ...);
我认为我必须使用反射,但我真的不知道如何向前发展。如何使用字符串路径名为UserControl生成正确的数据?
所有Google / SO结果都为我提供了解决我的ItemsSource问题(我没有)或我的DependencyProperty问题的答案(再次,非常确定我的工作正常)。我想通过在ItemsSource中使用用户指定的Paths来使我的UserControl更加灵活,以便将来可用。
答案 0 :(得分:0)
来自this answer的反射技术为解决方案奠定了基础:
var xValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.XValuesPath)
select property.GetValue(item)).ToArray();
var yValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.YValuesPath)
select property.GetValue(item)).ToArray();
然后可以将其分配给ActiveX控件
control.SetData(xValues, yValues, Title, ...);
如果需要特定类型,例如double[]
或DateTime[]
然后可以在linq语句中进行强制转换:
DateTime[] xValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.XValuesPath)
select (DateTime)property.GetValue(item)).ToArray();
double[] yValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.YValuesPath)
select (double)property.GetValue(item)).ToArray();
检查演员需要更多的工作:
DateTime dt = new DateTime();
DateTime[] xValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.XValuesPath)
let value = property.GetValue(item)
let castOK = DateTime.TryParse(value.ToString(), out dt)
select castOK ? dt : _defaultDateTimeValue).ToArray();
double d = new double();
double[] yValues = (from item in this.ItemsSource
let property = item.GetType().GetProperty(this.YValuesPath)
let value = property.GetValue(item)
let castOK = double.TryParse(value.ToString(), out d)
select castOK ? d : _defaultDoubleValue).ToArray();