在用户控件中更新 ItemsSource 后查看模型项目为空
View Model Items is Null after updating ItemsSource in User Control
我正在开发 WPF MVVM 应用程序,运行 遇到了问题。我熟悉 WPF 本身,但是我很少使用 MVVM,我怀疑我正在做一些 MVVM 不支持的事情,但是我不知道还有什么方法可以完成我想做的事情。
在应用程序中,我有一个名为 Agenda 的用户控件。它由几个控件组成,包括一个文本框、一个用于添加新议程项目的按钮和一个带有自定义模板的列表框。该模板包括一个扩展器,其中 header 是议程项目标题,up/down 箭头用于重新排序项目,以及一个用于删除项目的按钮。扩展器内容包含一个工具栏和一个富文本框。在 UC 议程中,我有一个名为 ItemsSource
的依赖项 属性,它是一个 IEnumerable<AgendaItem>
.
现在,我有一个名为 Appointment 的视图、其关联的 VM (AppointmentViewModel) 及其模型 (AppointmentModel)。在模型中,有一个名为 AgendaItems 的字段,它是一个 ObservableCollection<AgendaItem>
。议程 UC 在约会视图中使用,UC 的 ItemsSource
绑定到 Model.AgendaItems
(可观察的 collection)。
我遇到的问题是当我尝试处理按钮以重新排序 UC 中的议程项目时。例如,对于将议程项目向上移动列表的按钮,这是 UC 中的代码:
var tb = sender as Button;
var tag = tb.Tag as AgendaItem;
var lst = ItemsSource.ToList();
var index = lst.IndexOf(tag);
if(index > 0)
{
lst.RemoveAt(index);
lst.Insert(index - 1, tag);
ItemsSource = lst;
}
向上箭头的标签绑定到列表中的特定议程项目,因此我知道正在移动哪个项目。问题出现在我更新 ItemsSource
属性 做 ItemsSource = lst
之后。该行执行后,VM 中的 AgendaItems
ObservableCollection 为空。绑定模式设置为TwoWay
.
由于约会 UC 在应用程序中的各种 windows 中使用,对我来说,议程项目的重新排序应该由我的 UC 处理而不是在每个 window 使用了 UC。但是更新 UC 中的 ItemsSource
属性 会导致 VM 中的 collection 为空。
供参考,UC中的ItemsSource
属性定义为:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable<AgendaItem>), typeof(Agenda), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
有常规的 .NET 属性:
public IEnumerable<AgendaItem> ItemsSource
{
get => (IEnumerable<AgendaItem>)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
而OnItemsSourceChanged
方法是:
private static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is Agenda control)
{
if (e.OldValue is INotifyCollectionChanged oldValueINotifyCollectionChanged)
{
oldValueINotifyCollectionChanged.CollectionChanged -= control.ItemsSource_CollectionChanged;
}
if (e.NewValue is INotifyCollectionChanged newValueINotifyCollectionChanged)
{
newValueINotifyCollectionChanged.CollectionChanged += control.ItemsSource_CollectionChanged;
}
}
}
任何关于如何在不破坏 VM 的情况下重新排序 UC 中的 ItemsSource
collection 的 help/guidance 将不胜感激。提前谢谢你。
由于在 Enumerable 上调用 .ToList() 会创建新列表并将其重新分配给 ItemsSource
不起作用,因此可以将 ItemsSourceProperty
定义为 IList<AgendaItem>
因为这是接口您需要重新订购商品。
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IList<AgendaItem>), typeof(Agenda), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
(不要忘记更改 ItemsSource
属性 的签名)。
您还可以创建列表扩展方法以在您的代码中调用它,如下所示:
ItemsSource.Move(ItemsSource.IndexOf(tag), MoveDirection.Up);
public static void Move<T>(this IList<T> list, int iIndexToMove,
MoveDirection direction)
{
if (list.Count > 0 && (direction == MoveDirection.Down && iIndexToMove < list.Count - 1)
|| (direction == MoveDirection.Up && iIndexToMove > 0))
{
if (direction == MoveDirection.Up)
{
var old = list[iIndexToMove - 1];
list[iIndexToMove - 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
else
{
var old = list[iIndexToMove + 1];
list[iIndexToMove + 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
}
}
public enum MoveDirection
{
Up,
Down
}
通过将 ItemsSource
的数据类型从 IEnumerable<AgendaItem>
更改为 ObservableCollection<AgendaItem>
解决了该问题。感谢所有回复的人。非常感谢。
我正在开发 WPF MVVM 应用程序,运行 遇到了问题。我熟悉 WPF 本身,但是我很少使用 MVVM,我怀疑我正在做一些 MVVM 不支持的事情,但是我不知道还有什么方法可以完成我想做的事情。
在应用程序中,我有一个名为 Agenda 的用户控件。它由几个控件组成,包括一个文本框、一个用于添加新议程项目的按钮和一个带有自定义模板的列表框。该模板包括一个扩展器,其中 header 是议程项目标题,up/down 箭头用于重新排序项目,以及一个用于删除项目的按钮。扩展器内容包含一个工具栏和一个富文本框。在 UC 议程中,我有一个名为 ItemsSource
的依赖项 属性,它是一个 IEnumerable<AgendaItem>
.
现在,我有一个名为 Appointment 的视图、其关联的 VM (AppointmentViewModel) 及其模型 (AppointmentModel)。在模型中,有一个名为 AgendaItems 的字段,它是一个 ObservableCollection<AgendaItem>
。议程 UC 在约会视图中使用,UC 的 ItemsSource
绑定到 Model.AgendaItems
(可观察的 collection)。
我遇到的问题是当我尝试处理按钮以重新排序 UC 中的议程项目时。例如,对于将议程项目向上移动列表的按钮,这是 UC 中的代码:
var tb = sender as Button;
var tag = tb.Tag as AgendaItem;
var lst = ItemsSource.ToList();
var index = lst.IndexOf(tag);
if(index > 0)
{
lst.RemoveAt(index);
lst.Insert(index - 1, tag);
ItemsSource = lst;
}
向上箭头的标签绑定到列表中的特定议程项目,因此我知道正在移动哪个项目。问题出现在我更新 ItemsSource
属性 做 ItemsSource = lst
之后。该行执行后,VM 中的 AgendaItems
ObservableCollection 为空。绑定模式设置为TwoWay
.
由于约会 UC 在应用程序中的各种 windows 中使用,对我来说,议程项目的重新排序应该由我的 UC 处理而不是在每个 window 使用了 UC。但是更新 UC 中的 ItemsSource
属性 会导致 VM 中的 collection 为空。
供参考,UC中的ItemsSource
属性定义为:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable<AgendaItem>), typeof(Agenda), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
有常规的 .NET 属性:
public IEnumerable<AgendaItem> ItemsSource
{
get => (IEnumerable<AgendaItem>)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
而OnItemsSourceChanged
方法是:
private static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is Agenda control)
{
if (e.OldValue is INotifyCollectionChanged oldValueINotifyCollectionChanged)
{
oldValueINotifyCollectionChanged.CollectionChanged -= control.ItemsSource_CollectionChanged;
}
if (e.NewValue is INotifyCollectionChanged newValueINotifyCollectionChanged)
{
newValueINotifyCollectionChanged.CollectionChanged += control.ItemsSource_CollectionChanged;
}
}
}
任何关于如何在不破坏 VM 的情况下重新排序 UC 中的 ItemsSource
collection 的 help/guidance 将不胜感激。提前谢谢你。
由于在 Enumerable 上调用 .ToList() 会创建新列表并将其重新分配给 ItemsSource
不起作用,因此可以将 ItemsSourceProperty
定义为 IList<AgendaItem>
因为这是接口您需要重新订购商品。
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IList<AgendaItem>), typeof(Agenda), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
(不要忘记更改 ItemsSource
属性 的签名)。
您还可以创建列表扩展方法以在您的代码中调用它,如下所示:
ItemsSource.Move(ItemsSource.IndexOf(tag), MoveDirection.Up);
public static void Move<T>(this IList<T> list, int iIndexToMove,
MoveDirection direction)
{
if (list.Count > 0 && (direction == MoveDirection.Down && iIndexToMove < list.Count - 1)
|| (direction == MoveDirection.Up && iIndexToMove > 0))
{
if (direction == MoveDirection.Up)
{
var old = list[iIndexToMove - 1];
list[iIndexToMove - 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
else
{
var old = list[iIndexToMove + 1];
list[iIndexToMove + 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
}
}
public enum MoveDirection
{
Up,
Down
}
通过将 ItemsSource
的数据类型从 IEnumerable<AgendaItem>
更改为 ObservableCollection<AgendaItem>
解决了该问题。感谢所有回复的人。非常感谢。