winforms 防止组合框的下拉菜单在选择项之前折叠

hwazgwia  于 2023-02-19  发布在  其他
关注(0)|答案(1)|浏览(156)

我希望在点击“分页”按钮时,组合框的下拉菜单仍然打开,这样我就可以看到组合框项目中的分页结果,并且在选择组合框项目时下拉菜单关闭。
我的问题是当我点击分页中的按钮时,组合框的下拉菜单关闭了,所以我看不到分页的结果。
如何防止下拉组合框崩溃之前,在C#赢的形式选择项目?

技术组合框分页.cs

using static DiscountCard.View.CustomControl.CtechPagination;

namespace DiscountCard.View.CustomControl
{
    public partial class CtechComboBoxPagination : ComboBox
    {
        public CtechPagination? Pagination { get; set; }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
                return cp;
            }
        }

        public CtechComboBoxPagination()
        {
            InitializeComponent();

            DoubleBuffered = true;
            DropDownStyle = ComboBoxStyle.DropDownList;
            DrawMode = DrawMode.OwnerDrawFixed;
            Font = new Font("Consolas", 11F, FontStyle.Regular, GraphicsUnit.Point);

            Pagination = new CtechPagination();
            Pagination.SetInitialize(Enumerable.Range(0, 100).AsQueryable(), newContent: true, PaginationPosition.LastPage);
            Pagination.FirstPaginationButton_Click += Pagination_FirstPaginationButton_Click;
            Pagination.PrevPaginationButton_Click += Pagination_PrevPaginationButton_Click;
            Pagination.NextPaginationButton_Click += Pagination_NextPaginationButton_Click;
            Pagination.LastPaginationButton_Click += Pagination_LastPaginationButton_Click;
        }

        private void Pagination_FirstPaginationButton_Click(object? sender, EventArgs e)
        {
            DroppedDown = true;
        }
        private void Pagination_PrevPaginationButton_Click(object? sender, EventArgs e)
        {
            DroppedDown = true;
        }
        private void Pagination_NextPaginationButton_Click(object? sender, EventArgs e)
        {
            DroppedDown = true;
        }
        private void Pagination_LastPaginationButton_Click(object? sender, EventArgs e)
        {
            DroppedDown = true;
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            e.DrawBackground();

            if (e.Index < 0 || e.Index >= Items.Count)
            {
                return;
            }
            var item = Items[e.Index];
            String? text = item == null ? "(null)" : item.ToString();

            TextRenderer.DrawText(e.Graphics, text, e.Font, e.Bounds, e.ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);

            base.OnDrawItem(e);
        }

        protected override void OnDropDown(EventArgs e)
        {
            base.OnDropDown(e);

            if (Pagination == null)
            {
                return;
            }

            // for test
            if (Pagination.CurrentPage != null)
            {
                Items.Clear();
                for (int i = Pagination.CurrentPage.MinIndex; i <= Pagination.CurrentPage.MaxIndex; i++)
                {
                    Items.Add(i);
                }
            }

            Pagination.Margin = new Padding(0);
            Pagination.MinimumSize = new Size(this.Width, 30);

            ToolStripControlHost host = new ToolStripControlHost(Pagination);
            host.Padding = new Padding(0);

            ToolStripDropDown dropdown = new ToolStripDropDown();
            dropdown.Padding = new Padding(0);
            dropdown.Items.Add(host);
            if (this.Items.Count > 0)
            {
                dropdown.Show(this, 0, 3 + this.Height + (this.Items.Count * this.ItemHeight));
            }
        }
    }
}

计算分页.cs

using CardData.Ext.Mod.Logger;
using DiscountCard.Ext.Mod.General;
using DiscountCard.View.CustomControl.Pagination;

namespace DiscountCard.View.CustomControl
{
    public partial class CtechPagination : UserControl
    {
        public enum PaginationPosition
        {
            FirstPage,
            PreviousPage,
            NextPage,
            LastPage,
            CurrrentPage
        }

        public CtechPagination()
        {
            InitializeComponent();

            FirstPaginationButton.Click += OnFirstPaginationButton_Click;
            PrevPaginationButton.Click += OnPrevPaginationButton_Click;
            NextPaginationButton.Click += OnNextPaginationButton_Click;
            LastPaginationButton.Click += OnLastPaginationButton_Click;
        }

        public event EventHandler? FirstPaginationButton_Click;
        public event EventHandler? PrevPaginationButton_Click;
        public event EventHandler? NextPaginationButton_Click;
        public event EventHandler? LastPaginationButton_Click;
        protected virtual void OnFirstPaginationButton_Click(object? sender, EventArgs e)
        {
            try
            {
                if (Pages == null)
                {
                    return;
                }
                if (Pages.Count == 0)
                {
                    return;
                }

                PageIndex = 0;

                Page? firstPage = Pages[PageIndex];
                if (firstPage != null)
                {
                    PagesLabel.Text = String.Format("{0:N0} of {1:N0}", firstPage.MinIndex, firstPage.MaxIndex);
                    FirstPage = firstPage;

                    CurrentPage = firstPage;

                    FirstPaginationButton_Click?.Invoke(this, e);
                }
            }
            catch (Exception ex)
            {
                ExLogger.LogException(ex, "");
            }
        }
        protected virtual void OnPrevPaginationButton_Click(object? sender, EventArgs e)
        {
            try
            {
                if (Pages == null)
                {
                    return;
                }
                if (Pages.Count == 0)
                {
                    return;
                }

                --PageIndex;
                if (PageIndex < 0)
                {
                    PageIndex = 0;
                }

                Page? prevPage = Pages[PageIndex];
                if (prevPage != null)
                {
                    PagesLabel.Text = String.Format("{0:N0} of {1:N0}", prevPage.MinIndex, prevPage.MaxIndex);
                    PreviousPage = prevPage;

                    CurrentPage = prevPage;

                    PrevPaginationButton_Click?.Invoke(this, e);
                }
            }
            catch (Exception ex)
            {
                ExLogger.LogException(ex, "");
            }
        }
        protected virtual void OnNextPaginationButton_Click(object? sender, EventArgs e)
        {
            try
            {
                if (Pages == null)
                {
                    return;
                }
                if (Pages.Count == 0)
                {
                    return;
                }

                ++PageIndex;
                if (PageIndex > Pages.Count - 1)
                {
                    PageIndex = Pages.Count - 1;
                }

                Page? nextPage = Pages[PageIndex];
                if (nextPage != null)
                {
                    PagesLabel.Text = String.Format("{0:N0} of {1:N0}", nextPage.MinIndex, nextPage.MaxIndex);
                    NextPage = nextPage;

                    CurrentPage = nextPage;

                    NextPaginationButton_Click?.Invoke(this, e);
                }
            }
            catch (Exception ex)
            {
                ExLogger.LogException(ex, "");
            }
        }
        protected virtual void OnLastPaginationButton_Click(object? sender, EventArgs e)
        {
            try
            {
                if (Pages == null)
                {
                    return;
                }
                if (Pages.Count == 0)
                {
                    return;
                }

                PageIndex = Pages.Count - 1;

                Page? lastPage = Pages[PageIndex];
                if (lastPage != null)
                {
                    PagesLabel.Text = String.Format("{0:N0} of {1:N0}", lastPage.MinIndex, lastPage.MaxIndex);
                    LastPage = lastPage;

                    CurrentPage = lastPage;

                    LastPaginationButton_Click?.Invoke(this, e);
                }
            }
            catch (Exception ex)
            {
                ExLogger.LogException(ex, "");
            }
        }
        public void SetInitialize(IQueryable<int> source, bool newContent, PaginationPosition selectedPagination)
        {
            PageSize = Common.DEFAULT_PAGE_SIZE;

            TotalCount = source.Count();
            if (TotalCount <= 0)
            {
                return;
            }

            TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
            if (TotalPages <= 0)
            {
                return;
            }

            if (newContent)
            {
                Pages = new List<Page>();
                for (int i = 0; i < TotalPages; i++)
                {
                    IQueryable<int> indexes = (IQueryable<int>)source.Skip(i * PageSize).Take(PageSize);
                    if (indexes != null)
                    {
                        Page page = new Page();
                        page.MinIndex = 1 + indexes.Min();
                        page.MaxIndex = 1 + indexes.Max();
                        Pages.Add(page);
                    }
                }
            }

            if (Pages != null)
            {
                switch (selectedPagination)
                {
                    case PaginationPosition.FirstPage:
                        if (newContent)
                        {
                            PageIndex = 0;
                        }

                        Page? firstPage = Pages[PageIndex];
                        if (firstPage != null)
                        {
                            PagesLabel.Text = String.Format("{0:N0} of {1:N0}", firstPage.MinIndex, firstPage.MaxIndex);
                            FirstPage = firstPage;

                            CurrentPage = firstPage;
                        }
                        break;

                    case PaginationPosition.PreviousPage:
                        if (newContent)
                        {
                            --PageIndex;
                        }
                        if (PageIndex < 0)
                        {
                            PageIndex = 0;
                        }

                        Page? prevPage = Pages[PageIndex];
                        if (prevPage != null)
                        {
                            PagesLabel.Text = String.Format("{0:N0} of {1:N0}", prevPage.MinIndex, prevPage.MaxIndex);
                            PreviousPage = prevPage;

                            CurrentPage = prevPage;
                        }
                        break;

                    case PaginationPosition.NextPage:
                        if (newContent)
                        {
                            ++PageIndex;
                        }
                        if (PageIndex > Pages.Count - 1)
                        {
                            PageIndex = Pages.Count - 1;
                        }

                        Page? nextPage = Pages[PageIndex];
                        if (nextPage != null)
                        {
                            PagesLabel.Text = String.Format("{0:N0} of {1:N0}", nextPage.MinIndex, nextPage.MaxIndex);
                            NextPage = nextPage;

                            CurrentPage = nextPage;
                        }
                        break;

                    case PaginationPosition.LastPage:
                        if (newContent)
                        {
                            PageIndex = Pages.Count - 1;
                        }
                        if (PageIndex < 0)
                        {
                            PageIndex = 0;
                        }

                        Page? lastPage = Pages[PageIndex];
                        if (lastPage != null)
                        {
                            PagesLabel.Text = String.Format("{0:N0} of {1:N0}", lastPage.MinIndex, lastPage.MaxIndex);
                            LastPage = lastPage;

                            CurrentPage = lastPage;
                        }
                        break;

                    case PaginationPosition.CurrrentPage:
                        if (PageIndex < 0)
                        {
                            PageIndex = 0;
                        }
                        if (PageIndex > Pages.Count - 1)
                        {
                            PageIndex = Pages.Count - 1;
                        }

                        Page? curentPage = Pages[PageIndex];
                        if (curentPage != null)
                        {
                            PagesLabel.Text = String.Format("{0:N0} of {1:N0}", curentPage.MinIndex, curentPage.MaxIndex);
                            CurrentPage = curentPage;
                        }
                        break;
                }
            }
        }

        public int PageIndex { get; private set; }
        public int PageSize { get; private set; }
        public int TotalCount { get; private set; }
        public int TotalPages { get; private set; }
        public List<Page>? Pages { get; private set; }

        public Page? CurrentPage { get; private set; }
        public Page? FirstPage { get; private set; }
        public Page? PreviousPage { get; private set; }
        public Page? NextPage { get; private set; }
        public Page? LastPage { get; private set; }

    }
}

计算分页.设计器.cs

namespace DiscountCard.View.CustomControl
{
    partial class CtechPagination
    {
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.PaginationTableLayoutPanel = new DiscountCard.View.CustomControl.CtechTableLayoutPanel();
            this.FirstPaginationButton = new System.Windows.Forms.Button();
            this.PrevPaginationButton = new System.Windows.Forms.Button();
            this.NextPaginationButton = new System.Windows.Forms.Button();
            this.LastPaginationButton = new System.Windows.Forms.Button();
            this.PagesLabel = new System.Windows.Forms.Label();
            this.PaginationTableLayoutPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // PaginationTableLayoutPanel
            // 
            this.PaginationTableLayoutPanel.ColumnCount = 9;
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
            this.PaginationTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
            this.PaginationTableLayoutPanel.Controls.Add(this.FirstPaginationButton, 1, 0);
            this.PaginationTableLayoutPanel.Controls.Add(this.PrevPaginationButton, 3, 0);
            this.PaginationTableLayoutPanel.Controls.Add(this.NextPaginationButton, 5, 0);
            this.PaginationTableLayoutPanel.Controls.Add(this.LastPaginationButton, 7, 0);
            this.PaginationTableLayoutPanel.Controls.Add(this.PagesLabel, 4, 0);
            this.PaginationTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.PaginationTableLayoutPanel.Location = new System.Drawing.Point(0, 0);
            this.PaginationTableLayoutPanel.Name = "PaginationTableLayoutPanel";
            this.PaginationTableLayoutPanel.RowCount = 1;
            this.PaginationTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.PaginationTableLayoutPanel.Size = new System.Drawing.Size(816, 30);
            this.PaginationTableLayoutPanel.TabIndex = 0;
            // 
            // FirstPaginationButton
            // 
            this.FirstPaginationButton.Dock = System.Windows.Forms.DockStyle.Fill;
            this.FirstPaginationButton.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
            this.FirstPaginationButton.Location = new System.Drawing.Point(8, 3);
            this.FirstPaginationButton.Name = "FirstPaginationButton";
            this.FirstPaginationButton.Size = new System.Drawing.Size(44, 24);
            this.FirstPaginationButton.TabIndex = 0;
            this.FirstPaginationButton.Text = "⟨⟨";
            this.FirstPaginationButton.UseVisualStyleBackColor = true;
            // 
            // PrevPaginationButton
            // 
            this.PrevPaginationButton.Dock = System.Windows.Forms.DockStyle.Fill;
            this.PrevPaginationButton.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
            this.PrevPaginationButton.Location = new System.Drawing.Point(63, 3);
            this.PrevPaginationButton.Name = "PrevPaginationButton";
            this.PrevPaginationButton.Size = new System.Drawing.Size(44, 24);
            this.PrevPaginationButton.TabIndex = 1;
            this.PrevPaginationButton.Text = "⟨";
            this.PrevPaginationButton.UseVisualStyleBackColor = true;
            // 
            // NextPaginationButton
            // 
            this.NextPaginationButton.Dock = System.Windows.Forms.DockStyle.Fill;
            this.NextPaginationButton.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
            this.NextPaginationButton.Location = new System.Drawing.Point(709, 3);
            this.NextPaginationButton.Name = "NextPaginationButton";
            this.NextPaginationButton.Size = new System.Drawing.Size(44, 24);
            this.NextPaginationButton.TabIndex = 2;
            this.NextPaginationButton.Text = "⟩";
            this.NextPaginationButton.UseVisualStyleBackColor = true;
            // 
            // LastPaginationButton
            // 
            this.LastPaginationButton.Dock = System.Windows.Forms.DockStyle.Fill;
            this.LastPaginationButton.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
            this.LastPaginationButton.Location = new System.Drawing.Point(764, 3);
            this.LastPaginationButton.Name = "LastPaginationButton";
            this.LastPaginationButton.Size = new System.Drawing.Size(44, 24);
            this.LastPaginationButton.TabIndex = 3;
            this.LastPaginationButton.Text = "⟩⟩";
            this.LastPaginationButton.UseVisualStyleBackColor = true;
            // 
            // PagesLabel
            // 
            this.PagesLabel.AutoSize = true;
            this.PagesLabel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.PagesLabel.Location = new System.Drawing.Point(113, 0);
            this.PagesLabel.Name = "PagesLabel";
            this.PagesLabel.Size = new System.Drawing.Size(590, 30);
            this.PagesLabel.TabIndex = 4;
            this.PagesLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // CtechPagination
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.PaginationTableLayoutPanel);
            this.Margin = new System.Windows.Forms.Padding(0);
            this.Name = "CtechPagination";
            this.Size = new System.Drawing.Size(816, 30);
            this.PaginationTableLayoutPanel.ResumeLayout(false);
            this.PaginationTableLayoutPanel.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private CtechTableLayoutPanel PaginationTableLayoutPanel;
        private Button FirstPaginationButton;
        private Button PrevPaginationButton;
        private Button NextPaginationButton;
        private Button LastPaginationButton;
        private Label PagesLabel;
    }
}

7gyucuyw

7gyucuyw1#

据我所知,您已经为分页创建了一个UserControl,当您单击其中一个导航按钮时,它会导致下拉菜单出现不必要的关闭。

我能够重现您所描述的行为,然后能够通过为用户控件实现IMessageFilter来抑制它,以便拦截鼠标事件并在筛选器中将其标记为“已处理”(如果它们发生在UC的客户端矩形内)。

public partial class Pagination : UserControl, IMessageFilter
{
    public Pagination()
    {
        InitializeComponent();
        Application.AddMessageFilter(this);
        Disposed += (sender, e) =>Application.RemoveMessageFilter(this);
        PagesLabel.Text = $"Page {Page} of {Pages}";
    }

    const int WM_LBUTTONDOWN = 0x0201;
    const int WM_LBUTTONUP = 0x0202;
    public bool PreFilterMessage(ref Message m)
    {
        var client = PointToClient(MousePosition);
        switch (m.Msg)
        {
            case WM_LBUTTONDOWN:
                if (ClientRectangle.Contains(client))
                {
                    IterateControlTree((control) => hitTest(control, client));
                    return true;
                }
                break;
            case WM_LBUTTONUP:
                if(ClientRectangle.Contains(client))
                {
                    return true;
                }
                break;
        }
        return false;
    }
    .
    .
    .
}

需要说明的是,这意味着也不会发生Button.Click事件!因此,有必要迭代用户控件的Control树,以便对其包含的按钮控件执行点击测试。

bool IterateControlTree(Func<Control, bool> action, Control control = null)
{
    if (control == null) control = this;
    if(action(control)) return true;
    foreach (Control child in control.Controls)
    {
        if(IterateControlTree(action, child))
        {
            return true;
        }
    }
    return false;
}

例如,如果检测到在某个按钮的工作区矩形中单击,则可以修改Page属性,该属性进而激发一个事件,以便组合框作出React。

private bool hitTest(Control control, Point client)
{
    if (control.Bounds.Contains(client))
    {
        switch (control.Name)
        {
            case nameof(FirstPaginationButton): Page = 1; return true;
            case nameof(PrevPaginationButton): Page --; return true;
            case nameof(NextPaginationButton): Page ++; return true;
            case nameof(LastPaginationButton): Page = Pages; return true;
            default: break;
        }
    }
    return false;
}

如果有用的话,请随意浏览或clone我为测试这个答案而编写的代码。

相关问题