通过MVVM Light RelayCommand绑定泛型类型
我正在使用隐式数据模板,该模板应用于 ItemsControl 的项目:
<ItemsControl ItemsSource="{Binding Path=CategoryAttributeVMs}"/>
<DataTemplate DataType="{x:Type my:CategoryAttributeDateFieldVM}">
<DockPanel>
<.....>
<Button Command="{Binding Path=MainViewModel.CopyToChildrenCommand,
Source={StaticResource Locator}}"
CommandParameter="{Binding Mode=OneWay}">
</DockPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type my:CategoryAttributeIntegerFieldVM}">
<DockPanel>
<.....>
<Button Command="{Binding Path=MainViewModel.CopyToChildrenCommand,
Source={StaticResource Locator}}"
CommandParameter="{Binding Mode=OneWay}">
</DockPanel>
</DataTemplate>
这是数据绑定到我的 ViewModel,如下所示:
public abstract class CategoryAttributeVM
{
protected CategoryAttributeVM(ICategoryAttribute categoryAttribute)
{
_categoryAttribute = categoryAttribute;
}
private readonly ICategoryAttribute _categoryAttribute;
public string Name { get { return _categoryAttribute.Name; } }
public object Value { get { return _categoryAttribute.Value; } }
}
public abstract class CategoryAttributeVM<T> : CategoryAttributeVM
{
protected CategoryAttributeVM(ICategoryAttribute<T> categoryAttribute)
: base(categoryAttribute) { _categoryAttribute = categoryAttribute; }
private readonly ICategoryAttribute<T> _categoryAttribute;
public new T Value
{
get { return _categoryAttribute.Value; }
set { _categoryAttribute.Value = value; }
}
}
public class CategoryAttributeDateFieldVM : CategoryAttributeVM<DateTime?>
{
public CategoryAttributeDateFieldVM(ICategoryAttributeDateField categoryAttributeDateField)
: base(categoryAttributeDateField) { }
}
public class CategoryAttributeIntegerFieldVM: CategoryAttributeVM<Int32?>
{
public CategoryAttributeIntegerFieldVM(ICategoryAttributeIntegerField categoryAttributeIntegerField)
: base(categoryAttributeIntegerField) { }
}
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
CategoryAttributeVMs = new List<CategoryAttributeVM>( new CategoryAttributeVM[]
{
new CategoryAttributeDateFieldVM(new CategoryAttributeDateField("DateField", DateTime.Now)),
new CategoryAttributeIntegerFieldVM(new CategoryAttributeIntegerField("IntField", 123))
});
CategoryAttributeVM2s = new List<CategoryAttributeVM>(new CategoryAttributeVM[]
{
new CategoryAttributeDateFieldVM(new CategoryAttributeDateField("DateField", null)),
new CategoryAttributeIntegerFieldVM(new CategoryAttributeIntegerField("IntField", null))
});
CopyToChildrenCommand = new RelayCommand<CategoryAttributeVM>(DoCopyToChildrenCommand);
}
public IEnumerable<CategoryAttributeVM> CategoryAttributeVMs { get; private set; }
private IEnumerable<CategoryAttributeVM> CategoryAttributeVM2s { get; private set; }
// This an MVVM Light RelayCommand
public RelayCommand<CategoryAttributeVM> CopyToChildrenCommand { get; private set; }
private void DoCopyToChildrenCommand(CategoryAttributeVM ca)
{
foreach (var item in CategoryAttributeVM2s)
{
// How to copy the ca.Value to item.Value where ca and item are of the same type?
if (item.GetType() == ca.GetType())
item.Value = ca.Value; // !! No worky because item.Value refers to the CategoryAttributeVM.Value, which is a readonly Object property
}
}
}
如何从 CategoryAttributeVM2s 获取与“ca”类型匹配的对象? 我想我错过了一些基本的东西,但看不到它。
泛型方法会很好,但据我所知,RelayCommand 不能以这种方式变得通用:
// This would be great
private void DoCopyToChildrenCommand<T, U>(T ca) where T : CategoryAttributeVM<U>
{
foreach (var item in CategoryAttributeVM2s.OfType<T>())
item.Value = ca.Value; // item.Value is type U, which is perfect
}
// But this can't be, obviously
public RelayCommand<CategoryAttributeVM<U>> CopyToChildrenCommand<U> { get; private set; }
有什么想法吗?
I am using Implicit Data Templates which are applied to the items of an ItemsControl:
<ItemsControl ItemsSource="{Binding Path=CategoryAttributeVMs}"/>
<DataTemplate DataType="{x:Type my:CategoryAttributeDateFieldVM}">
<DockPanel>
<.....>
<Button Command="{Binding Path=MainViewModel.CopyToChildrenCommand,
Source={StaticResource Locator}}"
CommandParameter="{Binding Mode=OneWay}">
</DockPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type my:CategoryAttributeIntegerFieldVM}">
<DockPanel>
<.....>
<Button Command="{Binding Path=MainViewModel.CopyToChildrenCommand,
Source={StaticResource Locator}}"
CommandParameter="{Binding Mode=OneWay}">
</DockPanel>
</DataTemplate>
This is databound to my ViewModel like so:
public abstract class CategoryAttributeVM
{
protected CategoryAttributeVM(ICategoryAttribute categoryAttribute)
{
_categoryAttribute = categoryAttribute;
}
private readonly ICategoryAttribute _categoryAttribute;
public string Name { get { return _categoryAttribute.Name; } }
public object Value { get { return _categoryAttribute.Value; } }
}
public abstract class CategoryAttributeVM<T> : CategoryAttributeVM
{
protected CategoryAttributeVM(ICategoryAttribute<T> categoryAttribute)
: base(categoryAttribute) { _categoryAttribute = categoryAttribute; }
private readonly ICategoryAttribute<T> _categoryAttribute;
public new T Value
{
get { return _categoryAttribute.Value; }
set { _categoryAttribute.Value = value; }
}
}
public class CategoryAttributeDateFieldVM : CategoryAttributeVM<DateTime?>
{
public CategoryAttributeDateFieldVM(ICategoryAttributeDateField categoryAttributeDateField)
: base(categoryAttributeDateField) { }
}
public class CategoryAttributeIntegerFieldVM: CategoryAttributeVM<Int32?>
{
public CategoryAttributeIntegerFieldVM(ICategoryAttributeIntegerField categoryAttributeIntegerField)
: base(categoryAttributeIntegerField) { }
}
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
CategoryAttributeVMs = new List<CategoryAttributeVM>( new CategoryAttributeVM[]
{
new CategoryAttributeDateFieldVM(new CategoryAttributeDateField("DateField", DateTime.Now)),
new CategoryAttributeIntegerFieldVM(new CategoryAttributeIntegerField("IntField", 123))
});
CategoryAttributeVM2s = new List<CategoryAttributeVM>(new CategoryAttributeVM[]
{
new CategoryAttributeDateFieldVM(new CategoryAttributeDateField("DateField", null)),
new CategoryAttributeIntegerFieldVM(new CategoryAttributeIntegerField("IntField", null))
});
CopyToChildrenCommand = new RelayCommand<CategoryAttributeVM>(DoCopyToChildrenCommand);
}
public IEnumerable<CategoryAttributeVM> CategoryAttributeVMs { get; private set; }
private IEnumerable<CategoryAttributeVM> CategoryAttributeVM2s { get; private set; }
// This an MVVM Light RelayCommand
public RelayCommand<CategoryAttributeVM> CopyToChildrenCommand { get; private set; }
private void DoCopyToChildrenCommand(CategoryAttributeVM ca)
{
foreach (var item in CategoryAttributeVM2s)
{
// How to copy the ca.Value to item.Value where ca and item are of the same type?
if (item.GetType() == ca.GetType())
item.Value = ca.Value; // !! No worky because item.Value refers to the CategoryAttributeVM.Value, which is a readonly Object property
}
}
}
How can I get the objects from CategoryAttributeVM2s that match the type of 'ca'?
I think I am missing something elementary, but cannot see it.
The generics approach would be nice but AFAIK the RelayCommand cannot be made generic in that way:
// This would be great
private void DoCopyToChildrenCommand<T, U>(T ca) where T : CategoryAttributeVM<U>
{
foreach (var item in CategoryAttributeVM2s.OfType<T>())
item.Value = ca.Value; // item.Value is type U, which is perfect
}
// But this can't be, obviously
public RelayCommand<CategoryAttributeVM<U>> CopyToChildrenCommand<U> { get; private set; }
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不是 100% 确定我理解您的问题,但为什么不在您的
RelayCommand
中使用object
并使CanExecute()
方法返回 true仅当对象可以转换为您的泛型类型时?I'm not 100% sure I understand your question, but why not use
object
in yourRelayCommand
and make theCanExecute()
method return true only if the object can be cast to the your generic type?最后,我在
CategoryAttributeVM
和CategoryAttributeVM
上添加了抽象方法的重载:然后我可以在 DoCopyToChildrenCommand 中使用它:
In the end, I added an overload of an abstract method on
CategoryAttributeVM
andCategoryAttributeVM<T>
:I could then use this in DoCopyToChildrenCommand: