如何绑定到 XAML 中的泛型方法





0/5 (0投票)
如何在 XAML 中绑定到泛型方法。
正如一些使用过 XAML 和泛型的人可能知道的,XAML 目前不支持泛型(即不支持直接绑定使用泛型的函数)。
所以考虑一下这个问题。
我有一些在整个系统中使用的各种静态数据,这些数据存储在集合中(我使用的是 ObservableCollection<t>
类型的特定数据对象集合)。WPF UI 应该能够绑定到这些集合,而无需编写大量的 get {…}
属性。理想情况下,应该有一个方法返回请求的静态数据的正确类型。我的意思是,可能有很多静态数据,当然我们可以通过在静态数据集合上公开大量的属性来实现,但这在我看来有点过时了。我们也可以简单地接收一个 Object
并返回一个 ObservableCollection
,但这似乎也不对,不够类型安全,不太符合我的喜好。这个问题似乎需要一个更通用的解决方案。等等,.NET 不支持泛型吗?当然支持,太好了。所以也许我们应该尝试以下方法:
1: public ObservableCollection<T> GetForType<T>()
2: {
3: return (ObservableCollection<T>)
typeToCollectionLookup[typeof(T)];
4: }
这似乎符合问题领域,但我们如何在 XAML 中实现它呢?
不幸的是,我不知道如何在 XAML 中处理泛型方法调用。我知道有一个 ObjectDataProvider
对象,它有一个 Method
属性,允许在 XAML 中构建参数。但是,这意味着我们需要为我们打算使用上述方法的每种类型创建一个新的 ObjectDataProvider
,并配置相应的参数。这很糟糕。一定有更好的方法,对吧?
下面展示了一个附加属性,它可以与 ComboBox
控件一起使用,用于绑定,它将通过调用泛型方法填充 ComboBox.ItemsSource
属性。
所以在 XAML 中你只需要做的是
1: <Window x:Class=”GenericBinding.Window1″
2: xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
3: xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
4: xmlns:local=”clr-namespace:GenericBinding;assembly=”
5: Title=”Window1″ Height=”300″ Width=”300″>
6: <Grid>
7:
8:
9: <ComboBox
10: local:ComboBoxProps.BoundCollectionType=”local:Person”/>
11:
12:
13: </Grid>
14: </Window>
其中 ComboBoxProps.BoundCollectionTypeProperty
附加属性的声明如下:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Windows;
6: using System.Windows.Controls;
7: using System.Reflection;
8: using System.Collections;
9:
10: namespace GenericBinding
11: {
12: /// <summary>
13: /// Provides a mechanism for binding a ComboBox.ItemSource against
14: /// a generic method within the StaticData singleton. Where the generic
15: /// method has a signature as follows:
16: ///
17: /// public ObservableCollection<T> GetForType<T>()
18: /// </summary>
19: public class ComboBoxProps
20: {
21: #region BoundCollectionType
22:
23: /// <summary>
24: /// BoundCollectionType Attached Dependency Property
25: /// </summary>
26: public static readonly DependencyProperty
BoundCollectionTypeProperty =
27: DependencyProperty.RegisterAttached(
“BoundCollectionType”,
28: typeof(Type), typeof(ComboBoxProps),
29: new FrameworkPropertyMetadata(null,
30: new PropertyChangedCallback(
OnBoundCollectionTypeChanged)));
31:
32: /// <summary>
33: /// Gets the BoundCollectionType property.
34: /// </summary>
35: public static Type GetBoundCollectionType
(DependencyObject d)
36: {
37: return (Type)d.GetValue(
BoundCollectionTypeProperty);
38: }
39:
40: /// <summary>
41: /// Sets the BoundCollectionType property.
42: /// </summary>
43: public static void SetBoundCollectionType(
DependencyObject d, Type value)
44: {
45: d.SetValue(BoundCollectionTypeProperty, value);
46: }
47:
48: /// <summary>
49: /// Handles changes to the BoundCollectionType property.
50: /// Uses Reflection to obtain the method within the StaticData singleton class
51: /// that has the generic method that we need to use to get the values from.
52: /// The method will be marked with a custom ItemsSourceLookUpMethodAttribute
53: /// to indicate which method is to be used, to create a Dynamic call to
54: /// using the correct generic parameter.
55: /// </summary>
56: private static void OnBoundCollectionTypeChanged(DependencyObject d,
57: DependencyPropertyChangedEventArgs e)
58: {
59: ComboBox cbSource = d as ComboBox;
60: Type t = (Type)e.NewValue;
61: Type[] types = new Type[] { t };
62:
63: MethodInfo[] methods =
64: typeof(StaticData).GetMethods(BindingFlags.Public |
BindingFlags.Instance);
65:
66: foreach (MethodInfo method in methods)
67: {
68: //Didnt like looking up MethodInfo.Name based on a string as it could
69: //change, so use a custom attribute to look for on the method instead
70:
71: ItemsSourceLookUpMethodAttribute[] attribs =
72: (ItemsSourceLookUpMethodAttribute[])
73: method.GetCustomAttributes(
74: typeof(ItemsSourceLookUpMethodAttribute), true);
75:
76: //is this the correct MethodInfo to invoke
77: if (attribs.Length > 0)
78: {
79: // create the generic method
80: MethodInfo genericMethod = method.MakeGenericMethod(types);
81: cbSource.ItemsSource =
82: (IEnumerable)genericMethod.Invoke(StaticData.Instance,
83: BindingFlags.Instance, null, null, null);
84: }
85: }
86: }
87: #endregion
88: }
89: }
如果你想查看完整的示例,可以阅读 Codeproject 网站上显示的链接文章,了解更多信息
希望这能像对我一样对你有所帮助。祝你玩得开心!