WPF 自定义ComboBox

发布时间 2023-06-21 10:51:12作者: 盛沧海

需求

ComboBox下拉列表,在光标移出ComboBox后,下拉列表立即收起。

 

利用WPF的  自定义控件 继承于ComboBox开发项目中需要的JComboBox,其代码如下:

namespace FrameWPF
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:FrameWPF"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:FrameWPF;assembly=FrameWPF"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
    /// 并重新生成以避免编译错误:
    ///
    ///     在解决方案资源管理器中右击目标项目,然后依次单击
    ///     “添加引用”->“项目”->[浏览查找并选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <MyNamespace:JComboBox/>
    ///
    /// </summary>
    public class JComboBox : ComboBox
    {
        static JComboBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(JComboBox), new FrameworkPropertyMetadata(typeof(JComboBox)));
        }
        public JComboBox()
        {
            this.Loaded += JComboBox_Loaded;
        }

        private void JComboBox_Loaded(object sender, RoutedEventArgs e)
        {

            Popup popup = (Popup)this.Template.FindName("PART_Popup", this);
            if (popup != null)//JComboBox刚加载时Popup并未显示,故不能找到
            {
                popup.MouseLeave += Popup_MouseLeave;
                popup.MouseEnter += Popup_MouseEnter;

                timer = new System.Timers.Timer
                {
                    Interval = 1000
                };
                timer.Elapsed += Timer_Elapsed;
                this.DropDownOpened += JComboBox_DropDownOpened;
            }
        }

        private void JComboBox_DropDownOpened(object sender, EventArgs e)
        {
            timer?.Start();
        }

        System.Timers.Timer timer;
        private void Popup_MouseEnter(object sender, MouseEventArgs e)//由于定时器1S后会关闭Popup,若点开Popup 在1S内进入了Popup,则定时器停止。
        {
            timer.Stop();
        }

        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            timer.Stop();
            Application.Current.Dispatcher.Invoke(() =>
            {
                this.IsDropDownOpen = false;
            });
        }

        private void Popup_MouseLeave(object sender, MouseEventArgs e)
        {
            this.IsDropDownOpen = false;
        }
    }
}

代码中添加了一个定时器,是为了避免若你点开了下拉列表的Popup,但一直停在原处或移到了非Popup的地方,则1S后就关闭Popup。