0

我正在开发 WPF MVVM 应用程序并遇到问题。我对 WPF 本身很熟悉,但是我很少使用 MVVM,而且我怀疑我正在做一些 MVVM 不支持的事情,但是我不知道如何完成我想做的事情。

在应用程序中,我有一个名为 Agenda 的用户控件。它包含几个控件,包括一个文本框、一个添加新议程项目的按钮和一个带有自定义模板的列表框。该模板包括一个扩展器,其中标题是议程项目标题、用于重新排序项目的向上/向下箭头以及用于删除项目的按钮。扩展器内容包含一个工具栏和一个富文本框。在议程 UC 我有一个名为的依赖属性ItemsSource,它是一个IEnumerable<AgendaItem>.

现在,我有一个名为 Appointment 的视图、它的关联 VM (AppointmentViewModel) 和它的模型 (AppointmentModel)。在模型中,有一个名为 AgendaItems 的字段,它是一个ObservableCollection<AgendaItem>. 议程 UC 在约会视图中使用,并且 UCItemsSource绑定到Model.AgendaItems(可观察的集合)。

我遇到的问题是当我尝试处理按钮以重新排序 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。该行执行后,AgendaItemsVM 中的 ObservableCollection 为空。绑定模式设置为TwoWay

由于约会 UC 在应用程序的各个窗口中使用,因此对我来说,议程项目的重新排序应该由我的 UC 处理,而不是在每个使用 UC 的窗口中复制代码。但是更新ItemsSourceUC 中的属性会导致 VM 中的集合为空。

作为参考,ItemsSourceUC中的属性定义为:

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;
        }
    }
}

任何关于如何ItemsSource在不破坏 VM 的情况下在 UC 中重新排序集合的帮助/指导将不胜感激。先感谢您。

4

2 回答 2

0

通过更改ItemsSourcefrom的数据类型IEnumerable<AgendaItem>ObservableCollection<AgendaItem>解决问题。感谢所有回复的人。非常感谢。

于 2020-11-17T15:17:19.570 回答
0

由于在 Enumerable 上调用 .ToList() 会创建新列表并将其重新分配给它ItemsSource不起作用,因此可能将其定义为ItemsSourcePropertyIList<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
    }
于 2020-11-11T21:44:20.183 回答