绑定到可观察集合的数据网格在删除项时不会更新



这个WPF应用程序有四个主要视图。其中一个视图,我们叫它OrdersView,它有一个包含订单的DataGrid。这个的DataContext是一个ViewModel' OrdersViewModel',当然,它实现了INotifyPropertyChanged。网格的每一行都有一个按钮,用于查看订单的详细信息。该按钮通过Window服务打开一个新窗口,该窗口允许用户通过处理订单、添加更多项目或删除订单来更新订单。这个窗口持有一个名为'OrderDetailsView'的UserControl,当然它有一个'OrderDetailsViewModel'作为DataContext。我对"编辑订单"one_answers"处理订单"功能没有任何问题。问题是"删除命令"。此按钮绑定到ViewModel中的命令,该命令引发事件并将订单Id发送到应用程序主窗口中的侦听器,然后主窗口将此Id传递给'OrdersViewModel'中的方法,该方法具有在ObservableCollection中查找订单并将其删除的函数。项目被删除,我在调试器中看到了集合的变化,但是当"OrderDetailsView"关闭时,订单数据网格仍然有血腥的订单,只有当我导航到不同的视图并返回到它时,它才会刷新。我曾试图将RaisePropertyChanged方法放在集合的setter中,在删除方法的末尾使用属性Orders的名称,但不起作用。

数据网格是这样开始的:

<DataGrid ItemsSource="{Binding Path=Orders}"
Style="{DynamicResource DataGridStyle}">

ViewDetails按钮是:

<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="BtnOrderDetails"
Content="View"
Margin="1"
Command="{Binding DataContext.SeeOrderDetailsCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
CommandParameter="{Binding}" />
</DataTemplate>

OrdersViewModel类似于:

public class OrdersViewModel : ViewModelBase
{
private ObservableCollection<Order> _orders;
public OrdersViewModel(List<Order> orders)
{
Orders = new ObservableCollection<Order>(orders);
}
public ObservableCollection<Order> Orders
{
get => _orders;
set
{
_orders = value;
RaisePropertyChanged();
}
}
public void DeleteOrder(int id)
{
Orders.Remove(Orders
.FirstOrDefault(order => order.Id.Equals(id)));
RaisePropertyChanged(nameof(Orders));
}
}

查看详细信息按钮将带您到一个包含'OrderDetailsView'的新窗口,并有一个这样的按钮:

<Button x:Name="DeleteOrder"
Content="Delete order"
Grid.Row="2"
Margin="10,0,0,10"
Style="{StaticResource DeleteOrderButton}"
Command="{Binding DeleteOrderCommand}"/>

在这个视图的视图模型中,我有以下内容:

public DelegateCommand DeleteOrderCommand { get; private set; }

和构造函数中的

DeleteOrderCommand = new DelegateCommand(DeleteOrder, () => CanDelete);

方法引发一个事件(你是这么说的吗?):

private void DeleteOrder()
{
DeleteOrderRequested(Order.Id);
CloseWindow();
}
public event Action<int> DeleteOrderRequested = delegate { };

我的主窗口,它是通信的东西不同的视图模型捕获这个事件:

private void OnDeleteOrderRequested(int id)
{
OrdersViewModel.DeleteOrder(id);
}

我知道这是一个非常复杂的应用程序,对吧?

为什么,为什么,为什么视图没有收到项已被删除的通知??

有人能帮帮我吗?或者至少告诉我去哪里继续找?

谢谢堆!

我找到问题了。我用一个不那么优雅的开关语句来处理导航,它在主窗口中切换CurrentViewModel,它会随着数据模板而改变,所以当VM改变时,视图也会改变。可能不是很传统,但还算管用。问题是,在启动时,我分配CurrentViewModel到OrdersViewModel,然后把viewModel在一个属性中使用它以后,当我想回去。我应该用另一种方式来做,我已经这样做了,当应用启动时,我首先创建OrderViewModel,放入一个属性然后我将currentVM分配给那个VM。我注意到这是一个问题,因为当我从第一个视图导航离开然后返回时,删除函数实际上是有效的。MainWindowViewModel是这样的:

public MainWindowViewModel(IOrdersDataProvider ordersData, ViewModelBase currentViewModel, AddItemViewModel addItemViewModel, ViewModelFactory vMFactory)
{
_Data = ordersData;
_isModalOpen = false;
_currentViewModel = currentViewModel;
_addItemViewModel = addItemViewModel;
NavigateCommand = new RelayCommandT<string>(Navigate, () => OrderDetailsWindowsOpen);
SeeOrderDetailsCommand = new DelegateCommand<Order>(ViewOrderDetails);
CreateNewOrderCommand = new DelegateCommand(CreateNewOrder);
_vMFactory = vMFactory;
}

app. example .cs中的a ComposeObjects方法做了一些非常愚蠢的事情,比如:

private static void ComposeObjects(ViewModelFactory vMFactory)
{
var currentViewModel = vMFactory.CreateViewModel("Orders");
var addOrderViewModel = vMFactory.CreateViewModel("AddOrder");
var mainWindowViewModel = (MainWindowViewModel)vMFactory.CreateViewModel("MainWindow");
// Set up main ViewModel
mainWindowViewModel.AddOrderViewModel = (AddOrderViewModel)addOrderViewModel;
mainWindowViewModel.OrdersViewModel = (OrdersViewModel)currentViewModel;
mainWindowViewModel.SubscribeHandlersToEvents();
Application.Current.MainWindow = new MainWindow
{
DataContext = mainWindowViewModel
};
}

我把它改成这样:

private static void ComposeObjects(ViewModelFactory vMFactory)
{
// Get ViewModels
var addOrderViewModel = vMFactory.CreateViewModel("AddOrder");
var mainWindowViewModel = (MainWindowViewModel)vMFactory.CreateViewModel("MainWindow");
// Set up main ViewModel
mainWindowViewModel.AddOrderViewModel = (AddOrderViewModel)addOrderViewModel;
mainWindowViewModel.SubscribeHandlersToEvents();
Application.Current.MainWindow = new MainWindow
{
DataContext = mainWindowViewModel
};
}

我将MainWindowVM构造函数调整为:

public MainWindowViewModel(IOrdersDataProvider ordersData, ViewModelBase ordersViewModel, AddItemViewModel addItemViewModel, ViewModelFactory vMFactory)
{
_Data = ordersData;
_isModalOpen = false;
OrdersViewModel = (OrdersViewModel)ordersViewModel;
_currentViewModel = OrdersViewModel;
_addItemViewModel = addItemViewModel;
NavigateCommand = new RelayCommandT<string>(Navigate, () => OrderDetailsWindowsOpen);
SeeOrderDetailsCommand = new DelegateCommand<Order>(ViewOrderDetails);
CreateNewOrderCommand = new DelegateCommand(CreateNewOrder);
_vMFactory = vMFactory;
}

分配OrdersViewModel属性首先做到了这一点,当然,是混乱的,这是一个正在进行的工作,我将在接下来的几天实现一个像Ninject这样的容器。我现在可以睡觉了。