【问题标题】:WPF UserControl with ItemsSource pathname property like ComboBox 'SelectedValuePath'具有 ItemsSource 路径名属性的 WPF UserControl,例如 ComboBox 'SelectedValuePath'
【发布时间】:2014-05-20 16:24:39
【问题描述】:

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

我的 UserControl 有一个 ItemsSource DependencyProperty(以及其他各种)。我现在想要以与 ComboBox 具有 SelectedValuePathDisplayMemberPath 属性相同的方式实现“路径”属性,以使其成为独立模块。

目前:

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 中的数据使用用户指定的路径来使我的 UserControl 更加灵活,以便将来使用。

【问题讨论】:

    标签: c# wpf binding user-controls path


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-25
      • 2012-03-16
      • 1970-01-01
      • 2013-06-30
      • 2015-04-07
      • 1970-01-01
      • 2011-04-17
      • 2019-12-08
      相关资源
      最近更新 更多