2012-01-24 82 views
1

我使用的應用到一個ItemsControl的項目隱式數據模板:綁定泛型類型通過MVVM光RelayCommand

<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> 

這是數據綁定到我的視圖模型像這樣:

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'類型的對象嗎? 我想我錯過了一些基本的東西,但看不到它。

仿製藥的方法是不錯,但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; } 

任何想法?

回答

0

最後,我添加了一個抽象方法的重載上CategoryAttributeVMCategoryAttributeVM<T>

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; 
    } 
} 

然後我可以在DoCopyToChildrenCommand使用:

private void DoCopyToChildrenCommand(CategoryAttributeVM ca) 
{ 
    foreach (var attribute in CategoryAttributeVM2s) 
     attribute.UpdateValueFrom(ca); 
} 
0

我不是100%確定我理解你的問題,但爲什麼不在RelayCommand中使用object,並且只有當對象可以轉換爲你的泛型類型時才使CanExecute()方法返回true?

ICommand MyCommand { get; set; } 

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

感謝您的答覆。 不幸的是,我沒有T和U類型提供給DoCopyToChildrenCommand