如何制作绑定不同类型的用户控件?

时间:2015-09-23 07:36:36

标签: c# wpf data-binding

我想创建一个UserControl,用户可以在其中绑定多种类型的数据。通常我定义一个依赖属性,例如:

  public ObservableCollection<MyDataType1> Values
    {
        get { return (ObservableCollection<MyDataType1>)GetValue(ValuesProperty); }
        set { SetValue(ValuesProperty, value); }
    }

    public static readonly DependencyProperty ValuesProperty =
        DependencyProperty.Register(
            "Values", typeof(ObservableCollection<MyDataType1>),
            typeof(MyUserControl),
            new PropertyMetadata(
                null));

如何将某种类型的强制转换定义为MyDataType1?

示例:

public class MyDataType1
{
     string ID { get; set; }
     string Title { get; set; }
     SolidColorBrush Color { get; set; }
}

我希望也可以绑定:

ObservableCollection<int> TestCollection { get; set; }

我试图在MyDataType1中定义一个隐式转换:

static public implicit operator MyDataType1(int value)
    {
        return new MyDataType1()
        {
           ID = value,
           Color = Colors.Black,
           Title = "Not defined"
        };
    }

然而,当我用int整理集合时,我的控件并没有显示任何内容。

<ItemsControl ItemsSource="{Binding Values}" ItemTemplate="{StaticResource MyTemplate}" />

要实现这一目标,我 想要定义Converter

2 个答案:

答案 0 :(得分:2)

对象属性的绑定在运行时得到解决,这意味着你几乎可以在XAML中转储任何绑定,如果绑定不起作用,它就会忽略它。

使用此功能,可以有效地选择您将要使用的数据类型。我想说实现这一目标的最佳方法是使用interface。这是一个例子:

public interface IAwesome
{
    int ID { get; }
}

public class MegaClass : IAwesome
{
    public int ID { get; set; }
    ...
}

public class SuperClass : IAwesome
{
    public int ID { get; set; }
    ...
}

使用此方法,您的依赖项属性将如下所示:

public ObservableCollection<IAwesome> Values
{
    get { return (ObservableCollection<IAwesome>)GetValue(ValuesProperty); }
    set { SetValue(ValuesProperty, value); }
}

public static readonly DependencyProperty ValuesProperty =
    DependencyProperty.Register(
        "Values", typeof(ObservableCollection<IAwesome>),
        typeof(MyUserControl),
        new PropertyMetadata(
            null));

另外需要提及的是,您还可以使用键入的DataTemplate,请参阅此处:

<DataTemplate DataType="{x:Type MyNamespace:SomethingOrOther}">

这样您就可以为特定DataTemplate定义Type,因此即使您的收藏集是IAwesome的列表,它们也可能会在容器中以不同的方式显示已分配DataTemplate

这样做的好处是你的强类型C#仍然有效,但在你的场景中,我们需要使这甚至更多通用。

使用interface的方法并没有真正解决您的问题,因为int无法从IAwesome继承,所以如果您尝试,您将会遇到编译器错误将任何int值分配给此属性。解决这个问题的方法是使用object

public ObservableCollection<object> Values
{
    get { return (ObservableCollection<object>)GetValue(ValuesProperty); }
    set { SetValue(ValuesProperty, value); }
}

public static readonly DependencyProperty ValuesProperty =
    DependencyProperty.Register(
        "Values", typeof(ObservableCollection<object>),
        typeof(MyUserControl),
        new PropertyMetadata(
            null));

由于所有都继承自object,因此您可以将任意值添加到此集合中。

在你真正需要在C#中使用这个属性之前,这一切都很好。你会遇到很多麻烦,因为你需要强制这些对象到他们想要的类型。

在您不需要使用这些值的情况下,这应该足够了,否则,您可能需要重新考虑您的控件,也许它正在尝试太多事情

答案 1 :(得分:1)

ObservableCollection不是一个好主意。尝试访问一个尝试返回从依赖项属性获取的值的属性(比如在运行时将ObservableCollection绑定到它),并使用强制转换为ObservableCollection。它将炸弹。这是因为您的自定义数据类型不是从对象继承的。它违反了称为“协方差”的规则。我试过这种方法并走到了尽头。接口是唯一的出路。也许是动态物体。