2016-02-23 29 views
0

有沒有辦法在ToolStripSplitButton上有Checked狀態?我想要一個具有Checked屬性的ToolStripButton,以確定在我的應用程序窗口中是否顯示疊加層。我的用戶希望有直接的交互來控制疊加層的不透明度,爲此我想像有一個分離按鈕,其中輔助按鈕打開一個滑動條來控制不透明度。 (這當然不是標準功能,但我有信心能夠把它們放在一起)。WinForms中的ToolStripSplitButton可以具有Checked狀態嗎?

但是,ToolStripSplitButton沒有Checked屬性,所以我不能直接這樣做。我試着在它旁邊有一個標準的ToolStripButton和一個單獨的ToolStripSplitButton,DropDownButtonWidth = 11,Margin = -5,1,0,2,因此它看起來像屬於ToolStripButton。它看起來很好,但爲了完成它們作爲單個按鈕的錯覺,我需要讓它們同時使用相同的VisualStyles.PushButtonState進行繪製 - 所以當鼠標懸停在它們中的任何一個上時它們都會變熱。

首先,我嘗試在兩個按鈕上使用MouseEnter和MouseLeave事件來嘗試更改其他按鈕的背景顏色,但這沒有效果。然後,我嘗試使用每個按鈕的Paint事件來嘗試使用ButtonRenderer.DrawButton以PushButtonState = Hot來渲染它們,但這似乎並不奏效,並且變得非常混亂。似乎必須有更好的方法!

有沒有一個簡單的或至少是一個實際的解決方案呢?

編輯:我後的效果是這樣的:

Combined Check button with split drop-down

回答

0

,我想出瞭解決的辦法是由ToolStripSplitButton繼承創建自己的按鈕,添加自己的Checked屬性,然後在它手動繪製時檢查:

/// <summary> 
/// ToolStripSplitCheckButton adds a Check property to a ToolStripSplitButton. 
/// </summary> 
public partial class ToolStripSplitCheckButton : ToolStripSplitButton 
{ 
    //============================================================================== 
    // Inner class: ToolBarButonSplitCheckButtonEventArgs 
    //============================================================================== 

    /// <summary> 
    /// The event args for the check button click event. To be able to use the OnCheckedChanged 
    /// event, we must also record a dummy button as well as this one (hack). 
    /// </summary> 
    public class ToolBarButonSplitCheckButtonEventArgs : ToolBarButtonClickEventArgs 
    { 
     /// <summary> 
     /// Constructor. 
     /// </summary> 
     /// <param name="split_button">The sender split check button</param> 
     public ToolBarButonSplitCheckButtonEventArgs(ToolStripSplitCheckButton split_button) 
      : base(new ToolBarButton("Dummy Button"))  // Hack - Dummy Button is not used 
     { 
      SplitCheckButton = split_button; 
     } 

     /// <summary> 
     /// The ToolStripSplitCheckButton to be sent as an argument. 
     /// </summary> 
     public ToolStripSplitCheckButton SplitCheckButton { get; set; } 
    } 


    //========================================================================== 
    // Construction 

    public ToolStripSplitCheckButton() 
    { 
     m_checked = false; 
     m_mouse_over = false; 
    } 


    //========================================================================== 
    // Properties 

    /// <summary> 
    /// Indicates whether the button should toggle its Checked state on click. 
    /// </summary> 
    [Category("Behavior"), 
    Description("Indicates whether the item should toggle its selected state when clicked."), 
    DefaultValue(true)] 
    public bool CheckOnClick { get; set; } 

    /// <summary> 
    /// Indictates the Checked state of the button. 
    /// </summary> 
    [Category("Behavior"), 
    Description("Indicates whether the ToolStripSplitCheckButton is pressed in or not pressed in."), 
    DefaultValue(false)] 
    public bool Checked { get { return m_checked; } set { m_checked = value; } } 


    //========================================================================== 
    // Methods 

    /// <summary> 
    /// Toggle the click state on button click. 
    /// </summary> 
    protected override void OnButtonClick(EventArgs e) 
    { 
     if (CheckOnClick) { 
      m_checked = !m_checked; 
      // Raise the OnCheckStateChanged event when the button is clicked 
      if (OnCheckChanged != null) { 
       ToolBarButonSplitCheckButtonEventArgs args = new ToolBarButonSplitCheckButtonEventArgs(this); 
       OnCheckChanged(this, args); 
      } 
     } 
     base.OnButtonClick(e); 
    } 

    /// <summary> 
    /// On mouse enter, record that we are over the button. 
    /// </summary> 
    protected override void OnMouseEnter(EventArgs e) 
    { 
     m_mouse_over = true; 
     base.OnMouseEnter(e); 
     this.Invalidate(); 
    } 

    /// <summary> 
    /// On mouse leave, record that we are no longer over the button. 
    /// </summary> 
    protected override void OnMouseLeave(EventArgs e) 
    { 
     m_mouse_over = false; 
     base.OnMouseLeave(e); 
     this.Invalidate(); 
    } 

    /// <summary> 
    /// Paint the check highlight when required. 
    /// </summary> 
    protected override void OnPaint(PaintEventArgs e) 
    { 
     base.OnPaint(e); 
     if (m_checked) { 
      // I can't get the check + mouse over to render properly, so just give the button a colour fill - Hack 
      if (m_mouse_over) { 
       using (Brush brush = new SolidBrush(Color.FromArgb(64, SystemColors.MenuHighlight))) { 
        e.Graphics.FillRectangle(brush, ButtonBounds); 
       } 
      } 
      ControlPaint.DrawBorder(
       e.Graphics, 
       e.ClipRectangle,   // To draw around the button + drop-down 
       //this.ButtonBounds,  // To draw only around the button 
       SystemColors.MenuHighlight, 
       ButtonBorderStyle.Solid); 
     } 
    } 


    //========================================================================== 
    // Member Variables 

    // The delegate that acts as a signature for the function that is ultimately called 
    // when the OnCheckChanged event is triggered. 
    public delegate void SplitCheckButtonEventHandler(object source, EventArgs e); 
    public event SplitCheckButtonEventHandler OnCheckChanged; 

    private bool m_checked; 
    private bool m_mouse_over; 
} 

要使用這個,處理這個按鈕的OnCheckChanged事件。

但是,這有幾個笨拙的黑客。爲了能夠爲檢查按鈕引發OnCheckedChanged事件,除了實際的按鈕之外,事件參數還必須包含對未使用的虛擬按鈕的引用。即使在對各種渲染器進行實驗之後,我也無法使得渲染後的+鼠標與正常檢查按鈕完全相同,所以我只畫了一個顏色疊加層,這幾乎是正確的,但並不完全。

1

我建議你創建自己的UserControl並使用它作爲一個ToolStripItem

toolStripMenuItem.DropDownItems.Add(new ToolStripControlHost(new OverlayControl())); 

這裏是OverlayControl,這是從你的描述推導出一個簡單的例子(我建議你創建一個真正的UserControlDesigner)。

public class OverlayControl : UserControl 
{ 
    private readonly CheckBox _checkBox = new CheckBox(); 
    private readonly TrackBar _trackBar = new TrackBar(); 

    public ToolStripExtended() 
    { 
     _checkBox.Text = "Overlay"; 
     BackColor = SystemColors.Window; 
     _checkBox.AutoSize = true; 
     _trackBar.AutoSize = true; 
     var flowLayoutPanel = new FlowLayoutPanel {AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink}; 
     flowLayoutPanel.Controls.AddRange(new Control[] { _checkBox, _trackBar }); 
     Controls.Add(flowLayoutPanel); 
     AutoSize = true; 
     AutoSizeMode = AutoSizeMode.GrowAndShrink; 
     PerformLayout(); 
    } 
} 
+0

謝謝@Bioukh,這似乎是一個很好的方法。實際上,我是在按鈕上的檢查狀態之後,而不是下拉框中的複選框,並且我添加了一個圖像以使其更清晰。這個想法是讓按鈕本身切換覆蓋(打開或關閉),下拉控制不透明。我會繼續研究你的建議,看看我能否修改它來做我所需要的。再次感謝。 – DelftRed

相關問題