【问题标题】:Remove bound items from ListBox only when user clicks save button仅当用户单击保存按钮时才从 ListBox 中删除绑定项目
【发布时间】:2015-03-10 15:37:04
【问题描述】:

我将项目绑定到列表框,并且我已经实现了一个功能,可以在它们被选中并且用户按下 Delete 键时将其删除。目前,删除功能直接访问源。但是,除非用户先单击保存按钮,否则我不想修改源代码。

如何修改删除 ListBoxItems 以便在用户单击按钮之前不会更新我的源?

我绑定到的列表

public ObservableCollection<Process> Processes { get; set; }

删除函数

private void OnDeletePressed(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Delete)
    {
        foreach (Process item in ProcessListBox.SelectedItems.OfType<Process>().ToList())
        {
            SelectedRobot.Processes.Remove(item);
        }
    }
}

XAML

<ListBox x:Name="ProcessListBox" ItemsSource="{Binding Processes, UpdateSourceTrigger=Explicit}" KeyDown="OnDeletePressed">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Label Content="{Binding ProcessName}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【问题讨论】:

  • 也许您在 Process 对象上有一个名为 IsDeleted 的属性,并在用户单击删除按钮时将其设置为 true,然后在用户单击保存时从列表中删除该项目?
  • 在@Krishna 的评论的基础上,您可以向项目模板添加一个数据触发器(基于将IsDeleted 属性设置为true)将项目的可见性设置为@987654326 @ 并将父 ListBoxItemFocusable 属性设置为 false。这样,该项目将从视图中“消失”,但仍会在源列表中。
  • @StevenRands 另一种方法是绑定到 ICollectionView 并在 IsDeleted 上有一个过滤器。这样,该项目将从 UI 集合中消失,但仍将存在于源集合中:)

标签: c# wpf data-binding updatesourcetrigger


【解决方案1】:

一种选择是创建您的收藏的副本并保留原件。比如在初始化的某个地方,调用:

    List<Process> pOriginalList = null;

    pOriginalList = Processes.ToList();



    private void OnDeletePressed(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Delete)
        {
            foreach (Process item in ProcessListBox.SelectedItems.OfType<Process>().ToList())
            {
                this.Processes.Remove(item);
            }
        }
    }

    private void OnSaveClick(object sender, RoutedEventArgs e)
    {
        // do nothing -- Processes already is set
    }

    private void OnCancelClick(object sender, RoutedEventArgs e)
    {
        Processes.Clear();
        Processes = new ObservableCollection<Process>(pOriginalList);
        this.DataContext = null;
        this.DataContext = this;
    }

XAML:

<Window x:Class="ListCopy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <StackPanel>
            <Button Content="Save" Click="OnSaveClick" />
                <Button Content="Cancel" Click="OnCancelClick" />
            </StackPanel>
            <ListBox x:Name="ProcessListBox" ItemsSource="{Binding Processes, UpdateSourceTrigger=Explicit}" KeyDown="OnDeletePressed">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding ProcessName}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        </StackPanel>
    </Grid>
</Window>

这使操作明确说明您何时需要对源进行实际更新。注意:不建议这样设置 DataContext,只是为了强制在取消时刷新列表。

【讨论】:

  • 我想避免复制和重新绑定。似乎应该可以在触发 UpdateSourceTrigger 之前进行不应用于源的更改,就像 textbox 属性一样。
  • 是的,对于大型列表,我可以看到这样做的动机。如果您尝试删除具有选定索引的 ListBox.Items,它将引发异常: {"Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead."} 指向您的绑定源 (ItemsSource=过程)。如果不制作副本,不确定如何做到这一点。
  • 如果您希望实际项目从列表中消失,请保持原样,但创建另一个列表 (removedList) 并将项目添加到该列表中,然后再将其删除。如果你点击保存,保持进程不变,否则将removedList中的项目添加回进程。这避免了完整的副本。使用 Krishna 建议的方法需要更多的工作来删除(折叠)列表框中的项目,但也会提供一种创建自定义用户控件的方法,该控件会延迟自动更新源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-09
  • 2021-09-19
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
  • 2020-07-29
相关资源
最近更新 更多