【解决方案】ItemsControl删除元素,但仍然显示它们

来源:互联网 发布:网络情缘陈星 编辑:程序博客网 时间:2024/06/07 07:43

例如一个选手机号的程序,有一系列手机号可选。有些手机号已经被人选走了,列表仍然显示它们,但多加一条删除线,如图。

如图,淡色的、被线划掉的就是已经被选走的。这样的功能该如何实现呢?


具体要求

外界可以把这种控件视为ListBox,加元素就是Items.Add,删元素就是Items.Remove。外界不应去关心如何“假删”。

此控件的应用范围应更为广泛,允许用模板来自定义被删除后的显示。

另外,出于个人爱好,此控件内部应尽量简单,少写代码;不重复发明微软专家已经发明的轮子。

实现

 class RetainRemovedListBox : ListBox    {        public RetainRemovedListBox()        {            ((INotifyCollectionChanged)Items).CollectionChanged += Class1_CollectionChanged;        }        void Class1_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)        {            if (e.Action == NotifyCollectionChangedAction.Remove)            {                Items.Insert(e.OldStartingIndex, e.OldItems[0]);                EventHandler itemContainerGeneratorOnStatusChanged = null;                itemContainerGeneratorOnStatusChanged = (sender1, e1) =>                        {                            if (ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)                            {                                ItemContainerGenerator.StatusChanged -= itemContainerGeneratorOnStatusChanged;                                IsRemovedListBoxItem lbi = (IsRemovedListBoxItem)ItemContainerGenerator.ContainerFromItem(e.OldItems[0]);                                lbi.IsRemoved = true;                                lbi.IsEnabled = false;                            }                        };                ItemContainerGenerator.StatusChanged += itemContainerGeneratorOnStatusChanged;            }        }        protected override DependencyObject GetContainerForItemOverride()        {            return new IsRemovedListBoxItem();        }        protected override bool IsItemItsOwnContainerOverride(object item)        {            return item is IsRemovedListBoxItem;        }    }    class IsRemovedListBoxItem : ListBoxItem    {        public static readonly DependencyProperty IsRemovedProperty =             DependencyProperty.Register("IsRemoved", typeof(bool), typeof(IsRemovedListBoxItem), new FrameworkPropertyMetadata(false));        public bool IsRemoved        {            get { return (bool)GetValue(IsRemovedProperty); }            set { SetValue(IsRemovedProperty, value); }        }    }

简单解释一下。所谓删除元素,其实删完以后又加了回去,但给它的Container做了记号,于是能够呈现“被删除”的外观。

GetContainerForItemOverride的父类实现是new ListBoxItem。

如果需要真正清除被删除的元素,可以在RetainRemovedListBox里面添加一个方法,对Items里每个元素调用ItemContainerGenerator.ContainerFromItem,检查IsRemoved,然后再删。当然了,Class1_CollectionChanged又会把这个元素添加回去。我相信,勤劳勇敢的中国人能自己解决好这个问题的。

用法


<Window x:Class="WpfApplication1.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:WpfApplication1="clr-namespace:WpfApplication1"        Title="MainWindow">    <DockPanel>        <Button DockPanel.Dock="Top" Content="填充靓号" Padding="10,4" Click="Button_Click" />        <Button DockPanel.Dock="Bottom" Content="选择"  Padding="10,4" Click="Button2_Click" />        <WpfApplication1:RetainRemovedListBox x:Name="myItemsControl">            <WpfApplication1:RetainRemovedListBox.ItemTemplate>                <DataTemplate>                    <TextBlock Name="textBlock" Text="{Binding}"/>                    <DataTemplate.Triggers>                        <DataTrigger Binding="{Binding IsRemoved, RelativeSource={RelativeSource AncestorType=WpfApplication1:IsRemovedListBoxItem}}" Value="True">                            <Setter TargetName="textBlock" Property="TextDecorations" Value="Strikethrough"/>                        </DataTrigger>                    </DataTemplate.Triggers>                </DataTemplate>            </WpfApplication1:RetainRemovedListBox.ItemTemplate>        </WpfApplication1:RetainRemovedListBox>    </DockPanel></Window>

        private void Button2_Click(object sender, RoutedEventArgs e)        {            myItemsControl.Items.Remove(myItemsControl.SelectedItem);        }

填充靓号的代码属技术专利,就不给了。:)


原创粉丝点击