我正在WPF应用程序中实现附加行为。我需要将类型参数传递给行为,因此我可以在void NewRow(Table<T> table)
上调用方法SqliteBoundRow
。如果我在XAML中实例化一个对象,我会使用x:TypeArguments
传递一个类型参数,但是在设置附加行为时我没有看到这样做的方法,因为它使用静态属性。
附加行为的代码如下所示:
public abstract class SqliteBoundRow<T> where T : SqliteBoundRow<T>
{
public abstract void NewRow(Table<T> table);
}
public class DataGridBehavior<T> where T:SqliteBoundRow<T>
{
public static readonly DependencyProperty IsEnabledProperty;
static DataGridBehavior()
{
IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled",
typeof(bool), typeof(DataGridBehavior<T>),
new FrameworkPropertyMetadata(false, OnBehaviorEnabled));
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
private static void OnBehaviorEnabled(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs args)
{
var dg = dependencyObject as DataGrid;
dg.InitializingNewItem += DataGrid_InitializingNewItem;
}
private static void DataGrid_InitializingNewItem(object sender,
InitializingNewItemEventArgs e)
{
var table = (sender as DataGrid).ItemsSource as Table<T>;
(e.NewItem as T).NewRow(table);
}
}
XAML看起来像这样:
<DataGrid DataGridBehavior.IsEnabled="True">
<!-- DataGridBehavior needs a type parameter -->
</DataGrid>
我目前的解决方案是将DataGridBehavior包装在一个指定类型参数的派生类中。
答案 0 :(得分:6)
最简单的解决方案是您声明另一个Attached Property
,但类型为Type
以保存参数值。在这种情况下,您需要在Type
:
IsEnabled Attached Property
属性
<DataGrid DataGridBehavior.TypeParameter="{x:Type SomePrefix:SomeType}"
DataGridBehavior.IsEnabled="True" ... />
再看一下你的代码,似乎你的IsEnabled
属性除了在你的表中添加一个新行之外什么都不做......在这种情况下,你没有理由不能用{替换它{1}}并使用那个添加新行。
答案 1 :(得分:2)
我不认为WPF提供了一种优雅的语法方式来做你想做的事情。所以我正准备给Sheridan发一个类似的答案。也就是说,您可以提供Type类型的附加属性来确定泛型类型。然而,Sheridan打败了我。下面是一些示例代码,说明如何使用反射执行此操作:
的Xaml
<DataGrid behaviors:DataGridBehavior.InnerType="namespace:SqliteBoundRow"
behaviors:DataGridBehavior.IsEnabled="True">
</DataGrid>
背后的代码
public abstract class DataGridBehavior
{
private static readonly ConcurrentDictionary<Type, DataGridBehavior> Behaviors = new ConcurrentDictionary<Type, DataGridBehavior>();
public static readonly DependencyProperty IsEnabledProperty;
public static readonly DependencyProperty InnerTypeProperty;
static DataGridBehavior()
{
IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled",
typeof(bool), typeof(DataGridBehavior),
new FrameworkPropertyMetadata(false, OnBehaviorEnabled));
InnerTypeProperty = DependencyProperty.RegisterAttached("InnerType",
typeof(Type), typeof(DataGridBehavior));
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetInnerType(DependencyObject obj, Type value)
{
obj.SetValue(InnerTypeProperty, value);
}
public static Type GetInnerType(DependencyObject obj)
{
return (Type)obj.GetValue(InnerTypeProperty);
}
private static void OnBehaviorEnabled(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs args)
{
var innerType = GetInnerType(dependencyObject);
if (innerType == null)
throw new Exception("Missing inner type");
var behavior = Behaviors.GetOrAdd(innerType, GetBehavior);
behavior.OnEnabled(dependencyObject);
}
private static DataGridBehavior GetBehavior(Type innerType)
{
var behaviorType = typeof(DataGridBehavior<>).MakeGenericType(innerType);
var behavior = (DataGridBehavior)Activator.CreateInstance(behaviorType);
return behavior;
}
protected abstract void OnEnabled(DependencyObject dependencyObject);
}
public class DataGridBehavior<T> : DataGridBehavior
where T : SqliteBoundRow
{
protected override void OnEnabled(DependencyObject dependencyObject)
{
//dg.InitializingNewItem += DataGrid_InitializingNewItem;
}
private static void DataGrid_InitializingNewItem(object sender,
InitializingNewItemEventArgs e)
{
//var table = (sender as DataGrid).ItemsSource as Table<T>;
//(e.NewItem as T).NewRow(table);
}
}
public class SqliteBoundRow
{
}