0

我正在使用 MVVM 模式并且有一个未完全更新的数据绑定列表框。

有一个模型视图包含绑定到列表的可观察机器集合:

<ListBox Name="MachinesList"
                         Height="300" 
                         Width="290" 
                         DataContext="{Binding Path=AllMachines}"
                         SelectionMode="Single"
                         ItemsSource="{Binding}" SelectionChanged="MachinesList_SelectionChanged"
                         HorizontalAlignment="Right"
                         >

集合 AllMachines 包含一个可观察的 MachineModelViews 集合,这些集合又绑定到一个 MachineView,该 MachineView 显示机器的名称和位置:

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Label Name="NameLabel" Content="{Binding Path=Name}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Width="50" />
            <Label Content="Location:" Width="120"
                HorizontalAlignment="Right"
                HorizontalContentAlignment="Center"
                VerticalContentAlignment="Center"
                Target="{Binding ElementName=locationLabel}" 
            />
            <Label Content="{Binding Path=Location.Name}" Name="locationLabel" HorizontalContentAlignment="Center" Width="60"/>
</StackPanel>

问题:

当值被添加到集合中时,事情会更新。但是,当一台机器被删除时,只有绑定到 Location.Name 的标签会更新,其他两个仍保留在列表框中。我已经确认该集合实际上正在正确更新和删除 MachineModelView,但是带有名称的标签和带有“位置:”的“标签标签”如何继续存在,直到重新启动应用程序:

前:

在此处输入图像描述

删除后:

在此处输入图像描述

应用重启后:

在此处输入图像描述

删除按钮调用一个命令,该命令从支持 AllMachines 属性的私有成员和存储库(最终通过实体框架插入数据库)中删除项目:

    RelayCommand _deleteCommand;

    public ICommand DeleteCommand
    {
        get
        {
            if (_deleteCommand == null)
            {
                _deleteCommand = new RelayCommand(
                    param => this.Delete(),
                    null
                    );
            }
            return _deleteCommand;
        }
    }

    void Delete()
    {
        if (_selectedMachine != null && _machineRepository.GetMachines().
            Where(i => i.Name == _selectedMachine.Name).Count() > 0)
        {
            _machineRepository.RemoveMachine(_machineRepository.GetMachines().
                Where(i => i.Name == _selectedMachine.Name).First());
            _allMachines.Remove(_selectedMachine);
        }
    }

注意:AllMachines 中只能有一个具有名称的项目(这由存储库中的添加逻辑和命令本身处理),因此删除“第一个”应该没问题。

AllMachines 属性:

public ObservableCollection<MachineViewModel> AllMachines
    {
        get
        {
            if(_allMachines == null)
            {
                List<MachineViewModel> all = (from mach in _machineRepository.GetMachines()
                                              select new MachineViewModel(mach, _machineRepository)).ToList();
                _allMachines = new ObservableCollection<MachineViewModel>(all);
            }
            return _allMachines;
        }
        private set
        {
            _allMachines = value;
        }
    }

选择更改事件处理程序:

private void MachinesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count > 0 && e.AddedItems[0] is MachineViewModel)
            ((MachinesViewModel)this.DataContext).SelectedMachine = (MachineViewModel)e.AddedItems[0];
    }
4

4 回答 4

0
_machineRepository.RemoveMachine(_machineRepository.GetMachines().
            Where(i => i.Name == _selectedMachine.Name).First());
        AllMachines.Remove(_selectedMachine);

而不是字段 _allMachines.Remove 直接从属性 AllMachines 中删除,例如

AllMachines.删除

我希望这将有所帮助。

于 2012-07-30T04:15:15.053 回答
0

我发现了我的问题,真的很愚蠢:我有一个在存储库更新时触发的事件。在我只有一个添加命令之前,我正在添加在出现此问题时删除的功能。原来该事件正在由 MachinesModelView 处理以更新它的内部变量,该变量是 AllMachines 属性的源:

void OnMachineAddedToRepository(object sender, MachineAddedOrRemovedEventArgs e)
    {
        var viewModel = new MachineViewModel(e.NewMachine, _machineRepository);
        this.AllMachines.Add(viewModel);
    }

我修改了事件参数以在添加和删除之间切换,但忘记更新事件处理程序。现在它确实起作用了:

void OnMachineAddedOrRemovedFromRepository(object sender, MachineAddedOrRemovedEventArgs e)
    {
        if (e.Added)
        {
            var viewModel = new MachineViewModel(e.NewMachine, _machineRepository);
            this.AllMachines.Add(viewModel);
        }
        else if (AllMachines.Where(i => i.Name == e.NewMachine.Name).Count() > 0)
            AllMachines.Remove(AllMachines.Where(i => i.Name == e.NewMachine.Name).First());
    }

让这件事难以追踪的是,额外的项目只存在非常短暂的时间,直到删除命令的 AllMachines.Remove 部分运行。因此,检查预删除计数和删除后计数看起来是正确的,当从存储库中删除项目时,中间的胆量触发了一个事件,该事件将项目重新添加并使其处于这种奇怪的状态。有点奇怪,它始终只有 MachineModelView 的位置部分浮动。我现在只是让事件处理程序从 _allMachines 变量中添加或删除项目,并且不要在删除命令中明确地触及它(删除命令只是从存储库中删除它并让 UI 变量在几分之一秒内赶上需要触发事件)。感谢一群人的帮助。

于 2012-07-30T19:31:34.127 回答
0

如果你按照你在这里所说的方式编码,那么一切都应该工作。请发布缺少的代码片段:

  • 您的 AllMachines 财产
  • 您的 MachinesList_SelectionChanged 事件 <--在执行 MVVM 时,您几乎不需要这个

请调试您的 Delete() 方法以确保:_allMachines.Remove(_selectedMachine); 被击中并且机器确实从您的收藏中删除。

于 2012-07-30T07:48:37.133 回答
0

如果'AllMachines 是您实际的可观察集合,我会将 itemssource 绑定到该集合,而不是将其绑定到您的数据上下文,然后将您的视图模型绑定为您的数据上下文。在您的 itemssource 绑定之后调用 updatesourcetrigger 也可能会有所帮助。

 DataContext="{Binding Path=YourViewModel}"
                     SelectionMode="Single"
                     ItemsSource="{Binding AllMachines, UpdateSourceTrigger="PropertyChanged"}"

您可以在某些标签上以及绑定的位置上使用该 updatesourcetrigger。除此之外,您的 xaml 看起来还不错,在看到所有内容之前,任何人都很难真正说出来。

于 2012-07-30T01:04:07.093 回答