2015-02-10 168 views
0

我在我的viewmodel對象中有一個叫做Item的類和一個ObservableCollection<Item>。我已將它綁定到ListBox。但Item有一個名爲Stats的字段,它是一個List<Stat>,我想將它綁定到另一個ListBox。我無法將其設置爲ObservableCollection,因爲ItemStat都是將用於非wpf項目的單獨類庫的一部分。我正在開發它們,所以我可以做出我想要的任何更改,但我無法弄清楚我應該如何去做這件事。WPF:我如何觀察觀察對象的列表屬性

我想開發一個編輯器,以便可以從第一個列表中選擇一個項目並將Stats添加到所選項目(並進一步自定義這些統計信息)。

任何幫助將不勝感激。

回答

2

如果您不能修改項目持有多List<StatModifer>其他的東西,那麼你不能做你想做的。您需要製作一個ItemViewModel,其中包含ObserveableCollection<StatModifierViewModel>。然後放入ToModel()函數,完成後將它們轉換回模型表單。您必須通過視圖模型代理來執行所有讀取和寫入操作,以便引發您的事件。

public class ViewModel 
{ 
    public ObservableCollection<ItemViewModel> Items { get; set; } 

    public IEnumerable<StatModifierType> StatModifierTypes 
    { 
     get { return Enum.GetValues(typeof(StatModifierType)).Cast<StatModifierType>(); } 
    } 

    public ViewModel() 
    { 
     Items = new ObservableCollection<ItemViewModel>(); 
    } 
} 

public class ItemViewModel : INotifyPropertyChanged 
{ 
    public ItemViewModel(Item item) 
    { 
     if(item == null) 
      throw new ArgumentNullException("item"); 

     Name = item.Name; 
     Id = item.Id; 
     Description = item.Description; 

     //This converts our List<StatModifier> to a IEnumerable<StatModifierViewModel> 
     var enumerableOfStatViewModels = item.Stats.Select(x => new StatModifierViewModel(x)); 

     _stats = new ObservableCollection<StatModifierViewModel>(enumerableOfStatViewModels); 
    } 

    public Item ToModel() 
    { 
     var item = new Item(); 
     item.Name = Name; 
     item.Id = Id; 
     item.Description = Description; 

     //This converts our ObservableCollection<StatModifierViewModel> to a IEnumerable<StatModifier> 
     var enumerableOfStats = Stats.Select(x => x.StatModifierModel); 

     item.Stats = enumerableOfStats.ToList(); 
    } 

    private ObservableCollection<StatModifierViewModel> _stats; 
    private string _name; 
    private string _id; 
    private string _description; 

    public ObservableCollection<StatModifierViewModel> Stats 
    { 
     get { return _stats; } 
     set 
     { 
      if (Equals(value, _stats)) 
       return; 

      _stats = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      if (value == _name) 
       return; 

      _name = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string Id 
    { 
     get { return _id; } 
     set 
     { 
      if (value == _id) 
       return; 

      _id = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string Description 
    { 
     get { return _description; } 
     set 
     { 
      if (value == _description) 
       return; 

      _description = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

public class StatModifierViewModel : INotifyPropertyChanged 
{ 
    private readonly StatModifier _statModifier; 

    public StatModifierViewModel(StatModifier statModifier) 
    { 
     //This needs to not be null to not blow up the other functions. 
     if(statModifier == null) 
      throw new ArgumentNullException("statModifier"); 

     _statModifier = statModifier; 
    } 

    public string StatId 
    { 
     get { return _statModifier.StatId; } 
     set 
     { 
      if (Equals(_statModifier.StatId, value)) 
       return; 

      _statModifier.StatId = value; 
      OnPropertyChanged(); 
     } 
    } 

    public StatModifierType Type 
    { 
     get { return _statModifier.Type; } 
     set 
     { 
      if (Equals(_statModifier.Type, value)) 
       return; 

      _statModifier.Type = value; 
      OnPropertyChanged(); 
     } 
    } 

    public float Value 
    { 
     get { return _statModifier.Value; } 
     set 
     { 
      if (Equals(_statModifier.Value, value)) 
       return; 

      _statModifier.Value = value; 
      OnPropertyChanged(); 
     } 
    } 


    public StatModifier StatModifierModel 
    { 
     get { return _statModifier; } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
1

爲什麼不實施INotifyPropertyChanged

public class Stat : INotifyPropertyChanged 
{ 
    private int _your_property; 
    public int your_property { 
     get { return _your_property; } 
     set { 
      _your_property = value; 
      NotifyPropertyChanged("your_property"); 
     } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
    private void NotifyPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (null != handler) { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

我想觀察的領域是一個**列表 **,所以我想我應該創建自己的IList,INotifyPropertyChanged的捕捉添加和刪除事件? – Talemon 2015-02-10 22:31:12

+0

@Talemon也許我誤解了你的情況。你**可以**哪些類別,以及你**不能**編輯哪一個類別?你想監視物品數量或每件物品內容的變化嗎? – fillobotto 2015-02-10 22:37:00

+0

你可以在這裏看到這些類:http://pastebin.com/pmZdu34e 我已經將StatModifier作爲Stat來簡化問題,Stat在這種情況下是一個不同的類。問題是公共ObservableCollection Items {get;組; }被觀察到,但是沒有觀察到List 的Item's Stats字段。 – Talemon 2015-02-10 22:47:59

0

您可以爲Observable Stats創建一個屬性。請參閱下面的代碼。

class Item 
{ 
    private List<Stat> stat; 

    public List<Stat> Stats 
    { 
     get { return stat; } 
     set { stat = value; } 
    } 

    public ObservableCollection<Stat> ObservableStats 
    { 
     get { return new ObservableCollection<Stat>(stat); }    
    } 

} 
+0

它會連接到原始列表嗎?我覺得它只是創建一個與原始項目的新集合,但它不會將任何更改傳遞給原始。 – Talemon 2015-02-10 22:50:55