我有一个带有ListBox项目的屏幕。项目模板包含一个扩展器控件,其中包含标题中的一些数据以及扩展器内容部分中的一些数据。
ListBox ItemTemplate的数据模板与此类似:
<DataTemplate x:Key="MyTypeTemplate" DataType="{x:Type MyType}">
<Expander DataContext="{Binding}">
<Expander.Header>
<Canvas>
<TextBox Text="{Binding MyProperty}"/>
</Canvas>
</Expander.Header>
<Canvas>
<TextBox Text={Binding MyDetailedProperty}"/>
</Canvas>
</Expander>
</DataTemplate>
每当这些属性发生变化时,“MyProperty”或“MyDetailedProperty”都会发生变化,扩展器控件就会崩溃。我认为这与在数据更改时重新创建的Expander项目有关。
作为附加数据项,绑定到列表框的列表实现了IBindingList,因为它来自为.NET 2.0创建的库。由于时间限制,我无法使用ObservableCollection重新创建列表
答案 0 :(得分:0)
我最终将我的模型对象包装在一个视图对象中,该对象添加了一个IsExpandable属性,我可以绑定到Expanded IsExpanded属性然后公开数据。
这不是一个通用的解决方案,但它解决了我的直接问题。我看到的可能的问题是我没有探究过PropertyChanged和ListChanged事件是否会导致我的UI对象导致内存泄漏问题,但在我的情况下,每个对象应该只创建一次。
此外,不支持在集合更改中添加和删除之外的事件,但在我的情况下,我不会触发其他任何内容,因此我可以安全地忽略它们。
public class ExpandableItem<T> : INotifyPropertyChanged
where T: INotifyPropertyChanged
{
private bool m_isExpanded;
private readonly T m_data;
public ExpandableItem(T data)
{
m_data = data;
m_data.PropertyChanged +=
delegate
{
PropertyChanged(this, new PropertyChangedEventArgs("Data"));
};
}
public bool IsExpanded
{
get { return m_isExpanded; }
set
{
if (value != m_isExpanded)
{
m_isExpanded = value;
PropertyChanged(this, new PropertyChangedEventArgs("IsExpanded"));
}
}
}
public T Data
{
get
{
return m_data;
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
public class ExpandableList<TObject,TList> :
ObservableCollection<ExpandableItem<TObject>>
where TList : ObservableCollection<TObject>
where TObject : INotifyPropertyChanged
{
readonly TList m_list;
public ExpandableList(TList list)
: base(list.Select(obj=>new ExpandableItem<TObject>(obj)))
{
list.CollectionChanged += OnListChanged;
m_list = list;
}
public TList Data { get { return m_list; } }
private void OnListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
Insert(e.NewStartingIndex, e.NewItems[0]);
}
if (e.Action == NotifyCollectionChangedAction.Remove)
{
RemoveAt(e.OldStartingIndex);
}
}
}