C# 通过MVVM Light RelayCommand绑定泛型类型

C# 通过MVVM Light RelayCommand绑定泛型类型,c#,wpf,generics,mvvm,relaycommand,C#,Wpf,Generics,Mvvm,Relaycommand,我使用的隐式数据模板应用于ItemsControl的项: <ItemsControl ItemsSource="{Binding Path=CategoryAttributeVMs}"/> <DataTemplate DataType="{x:Type my:CategoryAttributeDateFieldVM}"> <DockPanel> <.....> <Button Command="{Bi

我使用的隐式数据模板应用于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
        }
    }
}
公共抽象类CategoryAttributeVM
{
受保护的CategoryAttributeVM(ICategoryAttribute categoryAttribute)
{
_类别属性=类别属性;
}
私有只读ICategoryAttribute _categoryAttribute;
公共字符串名称{get{return _categoryAttribute.Name;}}
公共对象值{get{return _categoryAttribute.Value;}}
}
公共抽象类CategoryAttributeVM:CategoryAttributeVM
{
受保护的CategoryAttributeVM(ICategoryAttribute categoryAttribute)
:base(categoryAttribute){u categoryAttribute=categoryAttribute;}
私有只读ICategoryAttribute _categoryAttribute;
公共新T值
{
获取{return\u categoryAttribute.Value;}
设置{u categoryAttribute.Value=Value;}
}
}
公共类CategoryAttributeDateFieldVM:CategoryAttributeVM
{
公共类别AttributedAteFieldVM(ICategoryAttributeDateField类别AttributedAteField)
:base(categoryAttributeDateField){}
}
公共类CategoryAttributeFieldVM:CategoryAttributeVM
{
公共类别TributeIntegerFieldVM(ICategoryAttributeIntegerField类别TributeIntegerField)
:base(CategoryAttributeField){}
}
公共类MainViewModel:ViewModelBase
{
公共主视图模型()
{
CategoryAttributeVMs=新列表(新CategoryAttributeVM[]
{
新CategoryAttributeDateFieldVM(新CategoryAttributeDateField(“DateField”,DateTime.Now)),
新类别TributteIntegerFieldVM(新类别TributteIntegerField(“IntField”,123))
});
CategoryAttributeVM2s=新列表(新CategoryAttributeVM[]
{
新CategoryAttributeDateFieldVM(新CategoryAttributeDateField(“日期字段”,null)),
新类别TributteIntegerFieldVM(新类别TributteIntegerField(“IntField”,null))
});
CopyToChildrenCommand=新的RelayCommand(DoCopyToChildrenCommand);
}
public IEnumerable CategoryAttributeVMs{get;private set;}
private IEnumerable CategoryAttributeVM2s{get;private set;}
//这是一个MVVM灯继电器命令
public RelayCommand CopyToChildrenCommand{get;private set;}
私有无效DoCopyToChildrenCommand(类别属性ca)
{
foreach(类别属性VM2S中的var项)
{
//如何将ca.Value复制到item.Value,其中ca和item的类型相同?
if(item.GetType()==ca.GetType())
item.Value=ca.Value;/!!没有工作,因为item.Value引用CategoryAttributeVM.Value,它是一个只读对象属性
}
}
}
如何从CategoryAttributeVM2中获取与“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; }
//这太好了
私有无效DoCopyToChildrenCommand(T ca),其中T:CategoryAttributeVM
{
foreach(CategoryAttributeVM2s.OfType()中的变量项)
item.Value=ca.Value;//item.Value是U类型,这是完美的
}
//但这显然不可能
public RelayCommand CopyToChildrenCommand{get;private set;}

有什么想法吗?

我不能100%肯定我理解你的问题,但是为什么不在
RelayCommand
中使用
object
,只有当对象可以转换为你的泛型类型时,才能使
CanExecute()
方法返回true

ICommand MyCommand { get; set; }

MyCommand = new RelayCommand<object>(
    param => DoCopyToChildrenCommand<T, U>(param as T),
    param => param is T);
ICommand MyCommand{get;set;}
MyCommand=新中继命令(
param=>DoCopyToChildrenCommand(参数为T),
param=>param是T);

最后,我在
CategoryAttributeVM
CategoryAttributeVM
上添加了一个抽象方法重载:


谢谢你的回复。不幸的是,我没有提供给DoCopyToChildrenCommand的T和U类型
public abstract class CategoryAttributeVM 
{ 
    <...>
    public abstract void UpdateValueFrom(CategoryAttributeVM sourceCategoryAttributeVM);
} 

public abstract class CategoryAttributeVM<T> : CategoryAttributeVM 
{
    <...>
    public override void UpdateValueFrom(CategoryAttributeVM sourceCategoryAttributeVM)
    {
        if (GetType() == sourceCategoryAttributeVM.GetType())
            Value = (T)sourceCategoryAttributeVM.Value;
    }
}
private void DoCopyToChildrenCommand(CategoryAttributeVM ca)
{
    foreach (var attribute in CategoryAttributeVM2s)
        attribute.UpdateValueFrom(ca);
}