c# - 通过 MVVM Light RelayCommand 绑定(bind)泛型类型

标签 c# wpf generics mvvm 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>

这是数据绑定(bind)到我的 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
        }
    }
}

如何从 CategoryAttributeVM2 中获取与“ca”类型匹配的对象?
我想我错过了一些基本的东西,但看不到它。

泛型方法会很好,但AFAIK 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; }

有任何想法吗?

最佳答案

我不是 100% 确定我理解你的问题,但为什么不使用 object在您的 RelayCommand并制作 CanExecute()仅当对象可以转换为您的泛型类型时,方法才返回 true?

ICommand MyCommand { get; set; }

MyCommand = new RelayCommand<object>(
    param => DoCopyToChildrenCommand<T, U>(param as T),
    param => param is T);

关于c# - 通过 MVVM Light RelayCommand 绑定(bind)泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8988875/

相关文章:

java - 什么是原始类型,为什么我们不应该使用它呢?

java - <T 扩展可识别<?扩展可序列化>>?

c# - 如何将 SqlException 消息操作为用户友好的消息

c# - 将按钮绑定(bind)到不同的 ViewModel [MVVM]

wpf - 使用信使将参数从一个 View 模型传递到另一个 View 模型

wpf - 图像的 ScaleTransform

c# - 第一次画面

c# - 通过反射访问/执行通用方法?

c# - 为什么 Java 没有方法委托(delegate)?

c# - 由于 unauthorized_client 错误无法获取 token