WPF:如何观察被观察对象的List属性

时间:2015-02-10 22:15:38

标签: c# wpf

我的viewmodel对象中有一个名为Item的类和一个ObservableCollection<Item>。我已将其绑定到ListBox。但Item有一个名为Stats的字段List<Stat>,我希望将其绑定到另一个ListBox。我无法将其设为ObservableCollection,因为ItemStat都是将在非wpf项目中使用的单独类库的一部分。我正在开发它们,所以我可以做任何我想要的改变,但我无法弄清楚我应该怎么做。

我正在尝试开发一个编辑器,这样就可以从第一个列表中选择一个项目并将统计数据添加到所选项目中(并进一步自定义这些统计数据)。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分: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 :(得分: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));
        }
    }
}

答案 2 :(得分: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); }            
    }

}