我有一个控件列表,其中每个控件都有ZIndex属性:
class WizardControl : INotifyPropertyChanged
{
public int ZIndex { get; set; /* set emits PropertyChanged event */}
}
class WizardStep
{
ObservableCollection<WizardControl> Controls { get; set; }
}
class Wizard
{
ObservableCollection<WizardStep> Steps { get; set; }
}
我还有TreeView
使用HierarchicalDataTemplate
,其中每个WizardStep
都有一个树节点,所有WizardControl
都是树叶。
现在我想通过ZIndex对控件进行排序。我找到了一个使用自定义Converter
(http://stackoverflow.com/a/5730402/69868)的解决方案,只要ZIndex没有改变就可以正常工作。
当ZIndex更改时,排序的CollectionView不会发出CollectionChanged事件,GUI也不会选择更改顺序。
我的问题:如何创建一个排序的集合,当由于排序值的变化而重新排序项目时会发出正确的事件?
答案 0 :(得分:0)
为此,您必须CollectionView
使用ObservableCollection
并CollectionView.SortDescriptions.Add(new SortDescription(ZIndex))
。
这样,只要observable集合中任何项目的ZIndex
发生更改,它就会自动在GUI上获取正确的排序位置。
答案 1 :(得分:0)
我猜你可以在集合中自己实现INotifyCollectionChanged接口,该集合可以监听属性更改事件的WizardControl参数,让您完全控制事情的完成方式。我已经提供了一些如何完成的小样本。
WizardControl.cs
public class WizardControl : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int zIndex;
PropertyChangedEventArgs zIndexArgs = new PropertyChangedEventArgs("ZIndex");
public int ZIndex
{
get { return zIndex; }
set
{
if (zIndex != value)
{
zIndex = value;
PropertyChangedEventHandler temp = PropertyChanged;
if (temp != null)
temp(this, zIndexArgs);
}
}
}
public override string ToString()
{
return zIndex.ToString();
}
}
WizardCollection.cs
public class WizardCollection : INotifyCollectionChanged, IEnumerable<WizardControl>
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
NotifyCollectionChangedEventArgs collectionChangedMoveArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
List<WizardControl> items = new List<WizardControl>();
public WizardControl this[int index]
{
get { return items[index]; }
}
public void Add(WizardControl item)
{
if (items == null) items = new List<WizardControl>();
items.Add(item);
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
NotifyCollectionChangedEventHandler temp = CollectionChanged;
if (temp != null)
temp(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
public void Remove(WizardControl item)
{
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
NotifyCollectionChangedEventHandler temp = CollectionChanged;
if (temp != null)
temp(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "ZIndex")
{
items = items.OrderBy(x => x.ZIndex).ToList();
NotifyCollectionChangedEventHandler temp = CollectionChanged;
if (temp != null)
temp(this, collectionChangedMoveArgs);
}
}
public IEnumerator<WizardControl> GetEnumerator()
{
return items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return items.GetEnumerator();
}
}
答案 2 :(得分:0)
ObservableCollection
仅在集合更改时引发PropertyChange
通知,而不是在集合中的对象发生更改时。
如果您想要这种行为,您必须自己添加。通常我会在CollectionChanged
事件中添加它。
public MyViewModel()
{
MyCollection.CollectionChanged += MyCollection_CollectionChanged;
}
void MyCollection_CollectionChanged(object sender, CollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach(MyItem item in e.NewItems)
item.PropertyChanged += MyItem_PropertyChanged;
if (e.OldItems != null)
foreach(MyItem item in e.OldItems)
item.PropertyChanged -= MyItem_PropertyChanged;
}
void MyItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Some Property")
{
// Do work
RaisePropertyChanged("MyCollection");
}
}
由于您在Collection上使用Converter,只需为集合引发PropertyChanged事件就可以重新运行转换器