WPF-002 下拉列表的简单实现

最近在一个WPF项目中用到一个下拉列表,随着用户输入字符而进行显示,使用了绑定等知识,虽然实现比较简单,可是在性能上也是想了很多办法终于才勉强可以用,与大家分享下。

用于页面绑定的模型类:

public class MainWindowModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<Content> names = new ObservableCollection<Content>();

        private bool popupIsOpen = false;

        public bool PopupIsOpen
        {
            get 
            { 
                return popupIsOpen;
            }

            set 
            { 
                popupIsOpen = value;

                this.PropertyChanged(this, new PropertyChangedEventArgs("PopupIsOpen"));
            }
        }

        public ObservableCollection<Content> Names
        {
            get
            {
                return this.names;
            }

            set
            {
                this.names = value;

                this.PropertyChanged(this, new PropertyChangedEventArgs("Names"));
            }
        }
    }

    public class Content
    {
        private string name=string.Empty;

        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                name = value;
            }
        }
    }

后台代码:

 /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowModel model = new MainWindowModel();

        private List<BackgroundWorker> threadPool = new List<BackgroundWorker>();

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = model;
        }

        /// <summary>
        /// 在此增加内容
        /// </summary>
        private void InitialSetValue()
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    this.model.Names.Clear();

                    for (int i = 0; i < 100; i++)
                    {
                        Content content = new Content();

                        content.Name = i.ToString() + i.ToString() + 
                            i.ToString() + i.ToString() + i.ToString();

                        this.model.Names.Add(content);
                    }
                }));
        }

        /// <summary>
        /// 下拉菜单消失要清空内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void popupContent_Closed(object sender, EventArgs e)
        {
            this.model.Names.Clear();
        }

        /// <summary>
        /// 文本框失去焦点,下拉列表隐藏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox1_LostFocus(object sender, RoutedEventArgs e)
        {
            this.model.PopupIsOpen = false;
        }

        /// <summary>
        /// 文字内容改变,下拉类表出现
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
        {
            this.model.PopupIsOpen = true;

            if (threadPool.Count > 0)
            {
                threadPool[0].CancelAsync();
            }

            threadPool.Clear();

            string key = this.textBox1.Text.Trim();

            if (string.IsNullOrEmpty(key))
            {
                this.model.PopupIsOpen = false;

                return;
            }

            BackgroundWorker worker = new BackgroundWorker();

            worker.WorkerReportsProgress = true;

            worker.WorkerSupportsCancellation = true;

            worker.DoWork += (o, p) =>
            {
                InitialSetValue();

                p.Result = this.model.Names;
            };

            worker.RunWorkerCompleted += (o, p) =>
            {
                this.model.Names = p.Result as ObservableCollection<Content>;

                if (this.model.Names.Count <= 0)
                {
                    this.model.PopupIsOpen = false;
                }
            };

            threadPool.Add(worker);

            Thread.Sleep(100);

            if (threadPool.Count > 0)
            {
                threadPool[0].RunWorkerAsync();
            }
        }

        /// <summary>
        /// 子项被选中,下拉列表消失
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void item_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var data = (sender as ListBox).SelectedItem as Content;

            if (data == null)
            {
                this.model.PopupIsOpen = false;

                return;
            }

            try
            {
                this.textBox1.TextChanged -= new TextChangedEventHandler(textBox1_TextChanged);

                var searchtext = data.Name;

                this.model.PopupIsOpen = false;
            }
            catch
            {
            }
            finally
            {
                this.textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged);
            }
        }
    }

页面代码:

 <Window x:Class="TestPopup.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>
        <TextBox Height="38" HorizontalAlignment="Left" Margin="71,89,0,0" LostFocus="textBox1_LostFocus" TextChanged="textBox1_TextChanged"
                 Name="textBox1" VerticalAlignment="Top" Width="236" />
        
        <Popup Name="popupContent" StaysOpen="False" IsOpen="{Binding PopupIsOpen}" Closed="popupContent_Closed"
               Placement="Bottom"  PlacementTarget="{Binding ElementName=textBox1}"  >
            
            <ListBox Name="contentItems" SelectionChanged="item_SelectionChanged"   ItemsSource="{Binding Names}"
                                 MinWidth="{Binding ElementName=textBox1, Path=ActualWidth}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Margin="5,5" FontSize="15" Text="{Binding Name}" Foreground="Gray"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Popup>
    </Grid>
</Window>

效果:

主要注意的有一点,下拉列表消失时一定要清除数据,不然下次显示的时候会很慢。在用的时候找了好久才发现这个问题。
详细工程:http://download.csdn.net/detail/yysyangyangyangshan/4762184

WPF Combobox是一个常见的下拉列表控件,它能够快速地展示和选择不同的选项。在某些情况下,我们需要实现 Combobox 的多选功能,以便用户能够选择多个选项。本文将为您详细介绍如何使用 WPF Combobox 实现多选。 实现多选的一种简单的方式是将 WPF Combobox 显示为列表框(ListBox),然后允许用户在列表中选择多个选项。要实现这样的多选功能,需要使用 ItemsControl 和 ListBox 控件。首先,使用ItemsControl将要用于展示的选项集合附加到 Combobox 上。 ```xaml <!--定义ItemsControl--> <ItemsControl ItemsSource="{Binding Selection}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" Margin="5" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> ``` 其中,`Selection`是选项的集合。接下来,将 Combobox 的模板更改为 ListBox,使其在下拉列表中显示所有选项。 ```xaml <!--定义Combobox--> <ComboBox x:Name="ComboBox"> <ComboBox.Template> <ControlTemplate TargetType="ComboBox"> <Grid> <ToggleButton x:Name="ToggleButton" Content="Click" /> <Popup x:Name="Popup"> <ListBox ItemsSource="{Binding Selection}" SelectionMode="Multiple" /> </Popup> </Grid> </ControlTemplate> </ComboBox.Template> </ComboBox> ``` 在 Combobox 的模板中,使用 ToggleButton 将 Popup 隐藏和显示。Popup 中包含 ListBox,且设置 SelectionMode 属性为 Multiple,使其能够选择多个选项。此时,每个选项在 Popup 中显示为 ListBox 中的一个项,而不是 Combobox 的下拉列表中的一个项。 在编写代码时,需要先将 Combobox 显示为 ListBox,然后使用 Popup 特性将其隐藏。此外,还需要为 ListBox 添加事件处理程序,以便在用户选择选项时更新组合框的选项集合。 ```c# //实现多选 ComboBox.IsEditable = true; var itemsControl = ((ComboBox)ComboBox).Template.FindName("PART_ItemList", ComboBox) as ItemsControl; var listBox = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as ListBox; if (listBox != null) { listBox.SelectionMode = SelectionMode.Multiple; listBox.SelectionChanged += listBox_SelectionChanged; } //更新选项 var listBox = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as ListBox; if (listBox != null) { listBox.SelectionChanged -= listBox_SelectionChanged; for (int i = 0; i < listBox.SelectedItems.Count; ++i) { Selection.Add(listBox.SelectedItems[i].ToString()); } listBox.SelectionChanged += listBox_SelectionChanged; } ``` 最后,用户选择多个选项时,会在 Selection 集合中添加选项,当用户关闭 Popup 时,将更新选项的 Text 和 Popup 的 IsOpen 属性。 如上所述,这是使用 WPF Combobox 实现多选的一种简单方法。我们先将 Combobox 显示为 ListBox,再使用 Popup 特性将Popup隐藏,然后添加事件处理程序以更新选项集合。这种方式虽然看起来有点繁琐,但要实现多选需要的代码量很少,而且在使用上比一些自定义控件的方式更灵活简便。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值