带有ItemsSource路径名属性的WPF UserControl,如ComboBox'SelectedValuePath'

时间:2014-05-20 16:24:40

标签: c# wpf binding user-controls path

我有一个用于ActiveX WinForms UserControl的WPF UserControl包装器,因此我可以正确使用MVVM / Bindings而无需从视图模型中操作UI。

我的UserControl有一个ItemsSource DependencyProperty(以及其他各种)。我现在想要的是以与ComboBox具有SelectedValuePathDisplayMemberPath属性相同的方式实现“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更加灵活,以便将来可用。

1 个答案:

答案 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();