Поделиться через


Практическое руководство. Отображение переключателей в элементе управления MenuStrip (Windows Forms)

Переключатели подобны флажкам за тем исключением, что одновременно может выбрать только один из них. По умолчанию в классе ToolStripMenuItem не реализована функциональность переключателей, однако в нем предусмотрена функциональность для создания флажков, на основе которой можно реализовать функциональность переключателей для пунктов меню в составе элемента управления MenuStrip.

Если свойство CheckOnClick пункта меню имеет значение true, пользователь может устанавливать или снимать флажок рядом с пунктом меню щелчком мыши. Свойство Checked показывает текущее состояние пункта меню. Для реализации базовой функциональности переключателей необходимо при выборе нового пункта меню присваивать свойству Checked ранее выбранного пункта значение false.

Следующие процедуры описывают реализацию этой и дополнительной функциональности в классе, наследуемом от класса ToolStripMenuItem. Для обеспечения надлежащего поведения и внешнего вида переключателей в классе ToolStripRadioButtonMenuItem переопределяются такие члены, как OnCheckedChanged и OnPaint. Кроме того, в данном классе переопределяется свойство Enabled с тем, чтобы пункты подменю были отключены, если не выбран родительский элемент

Реализация поведения переключателей

  1. Присвойте свойству CheckOnClick значение true, чтобы сделать возможным выделение пунктов меню.

    ' Called by all constructors to initialize CheckOnClick.
    Private Sub Initialize()
        CheckOnClick = True
    End Sub
    
    // Called by all constructors to initialize CheckOnClick.
    private void Initialize()
    {
        CheckOnClick = true;
    }
    
  2. Переопределите метод OnCheckedChanged для снятия выделения с ранее выбранного пункта при выборе нового.

    Protected Overrides Sub OnCheckedChanged(ByVal e As EventArgs)
    
        MyBase.OnCheckedChanged(e)
    
        ' If this item is no longer in the checked state or if its 
        ' parent has not yet been initialized, do nothing.
        If Not Checked OrElse Me.Parent Is Nothing Then Return
    
        ' Clear the checked state for all siblings. 
        For Each item As ToolStripItem In Parent.Items
    
            Dim radioItem As ToolStripRadioButtonMenuItem = _
                TryCast(item, ToolStripRadioButtonMenuItem)
            If radioItem IsNot Nothing AndAlso _
                radioItem IsNot Me AndAlso _
                radioItem.Checked Then
    
                radioItem.Checked = False
    
                ' Only one item can be selected at a time, 
                ' so there is no need to continue.
                Return
    
            End If
        Next
    
    End Sub
    
    protected override void OnCheckedChanged(EventArgs e)
    {
        base.OnCheckedChanged(e);
    
        // If this item is no longer in the checked state or if its 
        // parent has not yet been initialized, do nothing.
        if (!Checked || this.Parent == null) return;
    
        // Clear the checked state for all siblings. 
        foreach (ToolStripItem item in Parent.Items)
        {
            ToolStripRadioButtonMenuItem radioItem =
                item as ToolStripRadioButtonMenuItem;
            if (radioItem != null && radioItem != this && radioItem.Checked)
            {
                radioItem.Checked = false;
    
                // Only one item can be selected at a time, 
                // so there is no need to continue.
                return;
            }
        }
    }
    
  3. Переопределите метод OnClick так, чтобы при щелчке по уже выбранному пункту выделение не снималось.

    Protected Overrides Sub OnClick(ByVal e As EventArgs)
    
        ' If the item is already in the checked state, do not call 
        ' the base method, which would toggle the value. 
        If Checked Then Return
    
        MyBase.OnClick(e)
    End Sub
    
    protected override void OnClick(EventArgs e)
    {
        // If the item is already in the checked state, do not call 
        // the base method, which would toggle the value. 
        if (Checked) return;
    
        base.OnClick(e);
    }
    

Изменение внешнего вида переключателей

  1. Переопределите метод OnPaint, чтобы заменить стандартный флажок переключателем с помощью класса RadioButtonRenderer.

    ' Let the item paint itself, and then paint the RadioButton
    ' where the check mark is normally displayed.
    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    
        If Image IsNot Nothing Then
            ' If the client sets the Image property, the selection behavior
            ' remains unchanged, but the RadioButton is not displayed and the
            ' selection is indicated only by the selection rectangle. 
            MyBase.OnPaint(e)
            Return
        Else
            ' If the Image property is not set, call the base OnPaint method 
            ' with the CheckState property temporarily cleared to prevent
            ' the check mark from being painted.
            Dim currentState As CheckState = Me.CheckState
            Me.CheckState = CheckState.Unchecked
            MyBase.OnPaint(e)
            Me.CheckState = currentState
        End If
    
        ' Determine the correct state of the RadioButton.
        Dim buttonState As RadioButtonState = RadioButtonState.UncheckedNormal
        If Enabled Then
            If mouseDownState Then
                If Checked Then
                    buttonState = RadioButtonState.CheckedPressed
                Else
                    buttonState = RadioButtonState.UncheckedPressed
                End If
            ElseIf mouseHoverState Then
                If Checked Then
                    buttonState = RadioButtonState.CheckedHot
                Else
                    buttonState = RadioButtonState.UncheckedHot
                End If
            Else
                If Checked Then buttonState = RadioButtonState.CheckedNormal
            End If
        Else
            If Checked Then
                buttonState = RadioButtonState.CheckedDisabled
            Else
                buttonState = RadioButtonState.UncheckedDisabled
            End If
        End If
    
        ' Calculate the position at which to display the RadioButton.
        Dim offset As Int32 = CInt((ContentRectangle.Height - _
            RadioButtonRenderer.GetGlyphSize( _
            e.Graphics, buttonState).Height) / 2)
        Dim imageLocation As Point = New Point( _
            ContentRectangle.Location.X + 4, _
            ContentRectangle.Location.Y + offset)
    
        ' Paint the RadioButton. 
        RadioButtonRenderer.DrawRadioButton( _
            e.Graphics, imageLocation, buttonState)
    
    End Sub
    
    // Let the item paint itself, and then paint the RadioButton
    // where the check mark is normally displayed.
    protected override void OnPaint(PaintEventArgs e)
    {
        if (Image != null)
        {
            // If the client sets the Image property, the selection behavior
            // remains unchanged, but the RadioButton is not displayed and the
            // selection is indicated only by the selection rectangle. 
            base.OnPaint(e);
            return;
        }
        else
        {
            // If the Image property is not set, call the base OnPaint method 
            // with the CheckState property temporarily cleared to prevent
            // the check mark from being painted.
            CheckState currentState = this.CheckState;
            this.CheckState = CheckState.Unchecked;
            base.OnPaint(e);
            this.CheckState = currentState;
        }
    
        // Determine the correct state of the RadioButton.
        RadioButtonState buttonState = RadioButtonState.UncheckedNormal;
        if (Enabled)
        {
            if (mouseDownState)
            {
                if (Checked) buttonState = RadioButtonState.CheckedPressed;
                else buttonState = RadioButtonState.UncheckedPressed;
            }
            else if (mouseHoverState)
            {
                if (Checked) buttonState = RadioButtonState.CheckedHot;
                else buttonState = RadioButtonState.UncheckedHot;
            }
            else
            {
                if (Checked) buttonState = RadioButtonState.CheckedNormal;
            }
        }
        else
        {
            if (Checked) buttonState = RadioButtonState.CheckedDisabled;
            else buttonState = RadioButtonState.UncheckedDisabled;
        }
    
        // Calculate the position at which to display the RadioButton.
        Int32 offset = (ContentRectangle.Height -
            RadioButtonRenderer.GetGlyphSize(
            e.Graphics, buttonState).Height) / 2;
        Point imageLocation = new Point(
            ContentRectangle.Location.X + 4,
            ContentRectangle.Location.Y + offset);
    
        // Paint the RadioButton. 
        RadioButtonRenderer.DrawRadioButton(
            e.Graphics, imageLocation, buttonState);
    }
    
  2. Переопределите методы OnMouseEnter, OnMouseLeave, OnMouseDown и OnMouseUp, чтобы отслеживать состояние мыши, и обеспечьте правильное отображение состояния переключателя методом OnPaint.

    Private mouseHoverState As Boolean = False
    
    Protected Overrides Sub OnMouseEnter(ByVal e As EventArgs)
        mouseHoverState = True
    
        ' Force the item to repaint with the new RadioButton state.
        Invalidate()
    
        MyBase.OnMouseEnter(e)
    End Sub
    
    Protected Overrides Sub OnMouseLeave(ByVal e As EventArgs)
        mouseHoverState = False
        MyBase.OnMouseLeave(e)
    End Sub
    
    Private mouseDownState As Boolean = False
    
    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        mouseDownState = True
    
        ' Force the item to repaint with the new RadioButton state.
        Invalidate()
    
        MyBase.OnMouseDown(e)
    End Sub
    
    Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
        mouseDownState = False
        MyBase.OnMouseUp(e)
    End Sub
    
    private bool mouseHoverState = false;
    
    protected override void OnMouseEnter(EventArgs e)
    {
        mouseHoverState = true;
    
        // Force the item to repaint with the new RadioButton state.
        Invalidate();
    
        base.OnMouseEnter(e);
    }
    
    protected override void OnMouseLeave(EventArgs e)
    {
        mouseHoverState = false;
        base.OnMouseLeave(e);
    }
    
    private bool mouseDownState = false;
    
    protected override void OnMouseDown(MouseEventArgs e)
    {
        mouseDownState = true;
    
        // Force the item to repaint with the new RadioButton state.
        Invalidate();
    
        base.OnMouseDown(e);
    }
    
    protected override void OnMouseUp(MouseEventArgs e)
    {
        mouseDownState = false;
        base.OnMouseUp(e);
    }
    

Отключение пунктов подменю, если не выбран родительский элемент

  1. Переопределите свойство Enabled так, чтобы пункт был отключен, если свойство CheckOnClick родительского элемента имеет значение true, а свойство Checked имеет значение false.

    ' Enable the item only if its parent item is in the checked state 
    ' and its Enabled property has not been explicitly set to false. 
    Public Overrides Property Enabled() As Boolean
        Get
            Dim ownerMenuItem As ToolStripMenuItem = _
                TryCast(OwnerItem, ToolStripMenuItem)
    
            ' Use the base value in design mode to prevent the designer
            ' from setting the base value to the calculated value.
            If Not DesignMode AndAlso ownerMenuItem IsNot Nothing AndAlso _
                ownerMenuItem.CheckOnClick Then
                Return MyBase.Enabled AndAlso ownerMenuItem.Checked
            Else
                Return MyBase.Enabled
            End If
        End Get
    
        Set(ByVal value As Boolean)
            MyBase.Enabled = value
        End Set
    End Property
    
    // Enable the item only if its parent item is in the checked state 
    // and its Enabled property has not been explicitly set to false. 
    public override bool Enabled
    {
        get
        {
            ToolStripMenuItem ownerMenuItem =
                OwnerItem as ToolStripMenuItem;
    
            // Use the base value in design mode to prevent the designer
            // from setting the base value to the calculated value.
            if (!DesignMode &&
                ownerMenuItem != null && ownerMenuItem.CheckOnClick)
            {
                return base.Enabled && ownerMenuItem.Checked;
            }
            else return base.Enabled;
        }
        set
        {
            base.Enabled = value;
        }
    }
    
  2. Переопределите метод OnOwnerChanged, чтобы подписаться на событие CheckedChanged родительского элемента.

    ' When OwnerItem becomes available, if it is a ToolStripMenuItem 
    ' with a CheckOnClick property value of true, subscribe to its 
    ' CheckedChanged event. 
    Protected Overrides Sub OnOwnerChanged(ByVal e As EventArgs)
    
        Dim ownerMenuItem As ToolStripMenuItem = _
            TryCast(OwnerItem, ToolStripMenuItem)
    
        If ownerMenuItem IsNot Nothing AndAlso _
            ownerMenuItem.CheckOnClick Then
            AddHandler ownerMenuItem.CheckedChanged, New _
                EventHandler(AddressOf OwnerMenuItem_CheckedChanged)
        End If
    
        MyBase.OnOwnerChanged(e)
    
    End Sub
    
    // When OwnerItem becomes available, if it is a ToolStripMenuItem 
    // with a CheckOnClick property value of true, subscribe to its 
    // CheckedChanged event. 
    protected override void OnOwnerChanged(EventArgs e)
    {
        ToolStripMenuItem ownerMenuItem =
            OwnerItem as ToolStripMenuItem;
        if (ownerMenuItem != null && ownerMenuItem.CheckOnClick)
        {
            ownerMenuItem.CheckedChanged +=
                new EventHandler(OwnerMenuItem_CheckedChanged);
        }
        base.OnOwnerChanged(e);
    }
    
  3. В обработчике события CheckedChanged родительского элемента необходимо объявить элемент недействительным, чтобы он отображался как включенный.

    ' When the checked state of the parent item changes, 
    ' repaint the item so that the new Enabled state is displayed. 
    Private Sub OwnerMenuItem_CheckedChanged( _
        ByVal sender As Object, ByVal e As EventArgs)
        Invalidate()
    End Sub
    
    // When the checked state of the parent item changes, 
    // repaint the item so that the new Enabled state is displayed. 
    private void OwnerMenuItem_CheckedChanged(
        object sender, EventArgs e)
    {
        Invalidate();
    }
    

Пример

В следующем примере кода приводится полное описание класса ToolStripRadioButtonMenuItem, а также классов Form и Program для демонстрации поведения переключателей.

Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Windows.Forms.VisualStyles

Public Class ToolStripRadioButtonMenuItem
    Inherits ToolStripMenuItem

    Public Sub New()
        MyBase.New()
        Initialize()
    End Sub

    Public Sub New(ByVal text As String)
        MyBase.New(text, Nothing, CType(Nothing, EventHandler))
        Initialize()
    End Sub

    Public Sub New(ByVal image As Image)
        MyBase.New(Nothing, image, CType(Nothing, EventHandler))
        Initialize()
    End Sub

    Public Sub New(ByVal text As String, ByVal image As Image)
        MyBase.New(text, image, CType(Nothing, EventHandler))
        Initialize()
    End Sub

    Public Sub New(ByVal text As String, _
        ByVal image As Image, ByVal onClick As EventHandler)
        MyBase.New(text, image, onClick)
        Initialize()
    End Sub

    Public Sub New(ByVal text As String, ByVal image As Image, _
        ByVal onClick As EventHandler, ByVal name As String)
        MyBase.New(text, image, onClick, name)
        Initialize()
    End Sub

    Public Sub New(ByVal text As String, ByVal image As Image, _
        ByVal ParamArray dropDownItems() As ToolStripItem)
        MyBase.New(text, image, dropDownItems)
        Initialize()
    End Sub

    Public Sub New(ByVal text As String, ByVal image As Image, _
        ByVal onClick As EventHandler, ByVal shortcutKeys As Keys)
        MyBase.New(text, image, onClick)
        Initialize()
        Me.ShortcutKeys = shortcutKeys
    End Sub

    ' Called by all constructors to initialize CheckOnClick.
    Private Sub Initialize()
        CheckOnClick = True
    End Sub

    Protected Overrides Sub OnCheckedChanged(ByVal e As EventArgs)

        MyBase.OnCheckedChanged(e)

        ' If this item is no longer in the checked state or if its 
        ' parent has not yet been initialized, do nothing.
        If Not Checked OrElse Me.Parent Is Nothing Then Return

        ' Clear the checked state for all siblings. 
        For Each item As ToolStripItem In Parent.Items

            Dim radioItem As ToolStripRadioButtonMenuItem = _
                TryCast(item, ToolStripRadioButtonMenuItem)
            If radioItem IsNot Nothing AndAlso _
                radioItem IsNot Me AndAlso _
                radioItem.Checked Then

                radioItem.Checked = False

                ' Only one item can be selected at a time, 
                ' so there is no need to continue.
                Return

            End If
        Next

    End Sub

    Protected Overrides Sub OnClick(ByVal e As EventArgs)

        ' If the item is already in the checked state, do not call 
        ' the base method, which would toggle the value. 
        If Checked Then Return

        MyBase.OnClick(e)
    End Sub

    ' Let the item paint itself, and then paint the RadioButton
    ' where the check mark is normally displayed.
    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

        If Image IsNot Nothing Then
            ' If the client sets the Image property, the selection behavior
            ' remains unchanged, but the RadioButton is not displayed and the
            ' selection is indicated only by the selection rectangle. 
            MyBase.OnPaint(e)
            Return
        Else
            ' If the Image property is not set, call the base OnPaint method 
            ' with the CheckState property temporarily cleared to prevent
            ' the check mark from being painted.
            Dim currentState As CheckState = Me.CheckState
            Me.CheckState = CheckState.Unchecked
            MyBase.OnPaint(e)
            Me.CheckState = currentState
        End If

        ' Determine the correct state of the RadioButton.
        Dim buttonState As RadioButtonState = RadioButtonState.UncheckedNormal
        If Enabled Then
            If mouseDownState Then
                If Checked Then
                    buttonState = RadioButtonState.CheckedPressed
                Else
                    buttonState = RadioButtonState.UncheckedPressed
                End If
            ElseIf mouseHoverState Then
                If Checked Then
                    buttonState = RadioButtonState.CheckedHot
                Else
                    buttonState = RadioButtonState.UncheckedHot
                End If
            Else
                If Checked Then buttonState = RadioButtonState.CheckedNormal
            End If
        Else
            If Checked Then
                buttonState = RadioButtonState.CheckedDisabled
            Else
                buttonState = RadioButtonState.UncheckedDisabled
            End If
        End If

        ' Calculate the position at which to display the RadioButton.
        Dim offset As Int32 = CInt((ContentRectangle.Height - _
            RadioButtonRenderer.GetGlyphSize( _
            e.Graphics, buttonState).Height) / 2)
        Dim imageLocation As Point = New Point( _
            ContentRectangle.Location.X + 4, _
            ContentRectangle.Location.Y + offset)

        ' Paint the RadioButton. 
        RadioButtonRenderer.DrawRadioButton( _
            e.Graphics, imageLocation, buttonState)

    End Sub

    Private mouseHoverState As Boolean = False

    Protected Overrides Sub OnMouseEnter(ByVal e As EventArgs)
        mouseHoverState = True

        ' Force the item to repaint with the new RadioButton state.
        Invalidate()

        MyBase.OnMouseEnter(e)
    End Sub

    Protected Overrides Sub OnMouseLeave(ByVal e As EventArgs)
        mouseHoverState = False
        MyBase.OnMouseLeave(e)
    End Sub

    Private mouseDownState As Boolean = False

    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        mouseDownState = True

        ' Force the item to repaint with the new RadioButton state.
        Invalidate()

        MyBase.OnMouseDown(e)
    End Sub

    Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
        mouseDownState = False
        MyBase.OnMouseUp(e)
    End Sub

    ' Enable the item only if its parent item is in the checked state 
    ' and its Enabled property has not been explicitly set to false. 
    Public Overrides Property Enabled() As Boolean
        Get
            Dim ownerMenuItem As ToolStripMenuItem = _
                TryCast(OwnerItem, ToolStripMenuItem)

            ' Use the base value in design mode to prevent the designer
            ' from setting the base value to the calculated value.
            If Not DesignMode AndAlso ownerMenuItem IsNot Nothing AndAlso _
                ownerMenuItem.CheckOnClick Then
                Return MyBase.Enabled AndAlso ownerMenuItem.Checked
            Else
                Return MyBase.Enabled
            End If
        End Get

        Set(ByVal value As Boolean)
            MyBase.Enabled = value
        End Set
    End Property

    ' When OwnerItem becomes available, if it is a ToolStripMenuItem 
    ' with a CheckOnClick property value of true, subscribe to its 
    ' CheckedChanged event. 
    Protected Overrides Sub OnOwnerChanged(ByVal e As EventArgs)

        Dim ownerMenuItem As ToolStripMenuItem = _
            TryCast(OwnerItem, ToolStripMenuItem)

        If ownerMenuItem IsNot Nothing AndAlso _
            ownerMenuItem.CheckOnClick Then
            AddHandler ownerMenuItem.CheckedChanged, New _
                EventHandler(AddressOf OwnerMenuItem_CheckedChanged)
        End If

        MyBase.OnOwnerChanged(e)

    End Sub

    ' When the checked state of the parent item changes, 
    ' repaint the item so that the new Enabled state is displayed. 
    Private Sub OwnerMenuItem_CheckedChanged( _
        ByVal sender As Object, ByVal e As EventArgs)
        Invalidate()
    End Sub

End Class

Public Class Form1
    Inherits Form

    Private menuStrip1 As New MenuStrip()
    Private mainToolStripMenuItem As New ToolStripMenuItem()
    Private toolStripMenuItem1 As New ToolStripMenuItem()
    Private toolStripRadioButtonMenuItem1 As New ToolStripRadioButtonMenuItem()
    Private toolStripRadioButtonMenuItem2 As New ToolStripRadioButtonMenuItem()
    Private toolStripRadioButtonMenuItem3 As New ToolStripRadioButtonMenuItem()
    Private toolStripRadioButtonMenuItem4 As New ToolStripRadioButtonMenuItem()
    Private toolStripRadioButtonMenuItem5 As New ToolStripRadioButtonMenuItem()
    Private toolStripRadioButtonMenuItem6 As New ToolStripRadioButtonMenuItem()

    Public Sub New()

        Me.mainToolStripMenuItem.Text = "main"
        toolStripRadioButtonMenuItem1.Text = "option 1"
        toolStripRadioButtonMenuItem2.Text = "option 2"
        toolStripRadioButtonMenuItem3.Text = "option 2-1"
        toolStripRadioButtonMenuItem4.Text = "option 2-2"
        toolStripRadioButtonMenuItem5.Text = "option 3-1"
        toolStripRadioButtonMenuItem6.Text = "option 3-2"
        toolStripMenuItem1.Text = "toggle"
        toolStripMenuItem1.CheckOnClick = True

        mainToolStripMenuItem.DropDownItems.AddRange(New ToolStripItem() { _
            toolStripRadioButtonMenuItem1, toolStripRadioButtonMenuItem2, _
            toolStripMenuItem1})
        toolStripRadioButtonMenuItem2.DropDownItems.AddRange( _
            New ToolStripItem() {toolStripRadioButtonMenuItem3, _
            toolStripRadioButtonMenuItem4})
        toolStripMenuItem1.DropDownItems.AddRange(New ToolStripItem() { _
            toolStripRadioButtonMenuItem5, toolStripRadioButtonMenuItem6})

        menuStrip1.Items.AddRange(New ToolStripItem() {mainToolStripMenuItem})
        Controls.Add(menuStrip1)
        MainMenuStrip = menuStrip1
        Text = "ToolStripRadioButtonMenuItem demo"
    End Sub
End Class

Public Class Program

    <STAThread()> Public Shared Sub Main()
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        Application.Run(New Form1())
    End Sub

End Class
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

public class ToolStripRadioButtonMenuItem : ToolStripMenuItem
{
    public ToolStripRadioButtonMenuItem()
        : base()
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text)
        : base(text, null, (EventHandler)null)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(Image image)
        : base(null, image, (EventHandler)null)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text, Image image)
        : base(text, image, (EventHandler)null)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text, Image image,
        EventHandler onClick)
        : base(text, image, onClick)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text, Image image,
        EventHandler onClick, string name)
        : base(text, image, onClick, name)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text, Image image,
        params ToolStripItem[] dropDownItems)
        : base(text, image, dropDownItems)
    {
        Initialize();
    }

    public ToolStripRadioButtonMenuItem(string text, Image image,
        EventHandler onClick, Keys shortcutKeys)
        : base(text, image, onClick)
    {
        Initialize();
        this.ShortcutKeys = shortcutKeys;
    }

    // Called by all constructors to initialize CheckOnClick.
    private void Initialize()
    {
        CheckOnClick = true;
    }

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

        // If this item is no longer in the checked state or if its 
        // parent has not yet been initialized, do nothing.
        if (!Checked || this.Parent == null) return;

        // Clear the checked state for all siblings. 
        foreach (ToolStripItem item in Parent.Items)
        {
            ToolStripRadioButtonMenuItem radioItem =
                item as ToolStripRadioButtonMenuItem;
            if (radioItem != null && radioItem != this && radioItem.Checked)
            {
                radioItem.Checked = false;

                // Only one item can be selected at a time, 
                // so there is no need to continue.
                return;
            }
        }
    }

    protected override void OnClick(EventArgs e)
    {
        // If the item is already in the checked state, do not call 
        // the base method, which would toggle the value. 
        if (Checked) return;

        base.OnClick(e);
    }

    // Let the item paint itself, and then paint the RadioButton
    // where the check mark is normally displayed.
    protected override void OnPaint(PaintEventArgs e)
    {
        if (Image != null)
        {
            // If the client sets the Image property, the selection behavior
            // remains unchanged, but the RadioButton is not displayed and the
            // selection is indicated only by the selection rectangle. 
            base.OnPaint(e);
            return;
        }
        else
        {
            // If the Image property is not set, call the base OnPaint method 
            // with the CheckState property temporarily cleared to prevent
            // the check mark from being painted.
            CheckState currentState = this.CheckState;
            this.CheckState = CheckState.Unchecked;
            base.OnPaint(e);
            this.CheckState = currentState;
        }

        // Determine the correct state of the RadioButton.
        RadioButtonState buttonState = RadioButtonState.UncheckedNormal;
        if (Enabled)
        {
            if (mouseDownState)
            {
                if (Checked) buttonState = RadioButtonState.CheckedPressed;
                else buttonState = RadioButtonState.UncheckedPressed;
            }
            else if (mouseHoverState)
            {
                if (Checked) buttonState = RadioButtonState.CheckedHot;
                else buttonState = RadioButtonState.UncheckedHot;
            }
            else
            {
                if (Checked) buttonState = RadioButtonState.CheckedNormal;
            }
        }
        else
        {
            if (Checked) buttonState = RadioButtonState.CheckedDisabled;
            else buttonState = RadioButtonState.UncheckedDisabled;
        }

        // Calculate the position at which to display the RadioButton.
        Int32 offset = (ContentRectangle.Height -
            RadioButtonRenderer.GetGlyphSize(
            e.Graphics, buttonState).Height) / 2;
        Point imageLocation = new Point(
            ContentRectangle.Location.X + 4,
            ContentRectangle.Location.Y + offset);

        // Paint the RadioButton. 
        RadioButtonRenderer.DrawRadioButton(
            e.Graphics, imageLocation, buttonState);
    }

    private bool mouseHoverState = false;

    protected override void OnMouseEnter(EventArgs e)
    {
        mouseHoverState = true;

        // Force the item to repaint with the new RadioButton state.
        Invalidate();

        base.OnMouseEnter(e);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        mouseHoverState = false;
        base.OnMouseLeave(e);
    }

    private bool mouseDownState = false;

    protected override void OnMouseDown(MouseEventArgs e)
    {
        mouseDownState = true;

        // Force the item to repaint with the new RadioButton state.
        Invalidate();

        base.OnMouseDown(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        mouseDownState = false;
        base.OnMouseUp(e);
    }

    // Enable the item only if its parent item is in the checked state 
    // and its Enabled property has not been explicitly set to false. 
    public override bool Enabled
    {
        get
        {
            ToolStripMenuItem ownerMenuItem =
                OwnerItem as ToolStripMenuItem;

            // Use the base value in design mode to prevent the designer
            // from setting the base value to the calculated value.
            if (!DesignMode &&
                ownerMenuItem != null && ownerMenuItem.CheckOnClick)
            {
                return base.Enabled && ownerMenuItem.Checked;
            }
            else return base.Enabled;
        }
        set
        {
            base.Enabled = value;
        }
    }

    // When OwnerItem becomes available, if it is a ToolStripMenuItem 
    // with a CheckOnClick property value of true, subscribe to its 
    // CheckedChanged event. 
    protected override void OnOwnerChanged(EventArgs e)
    {
        ToolStripMenuItem ownerMenuItem =
            OwnerItem as ToolStripMenuItem;
        if (ownerMenuItem != null && ownerMenuItem.CheckOnClick)
        {
            ownerMenuItem.CheckedChanged +=
                new EventHandler(OwnerMenuItem_CheckedChanged);
        }
        base.OnOwnerChanged(e);
    }

    // When the checked state of the parent item changes, 
    // repaint the item so that the new Enabled state is displayed. 
    private void OwnerMenuItem_CheckedChanged(
        object sender, EventArgs e)
    {
        Invalidate();
    }

}

public class Form1 : Form
{
    private MenuStrip menuStrip1 = new MenuStrip();
    private ToolStripMenuItem mainToolStripMenuItem = new ToolStripMenuItem();
    private ToolStripMenuItem toolStripMenuItem1 = new ToolStripMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem1 = 
        new ToolStripRadioButtonMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem2 = 
        new ToolStripRadioButtonMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem3 = 
        new ToolStripRadioButtonMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem4 = 
        new ToolStripRadioButtonMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem5 = 
        new ToolStripRadioButtonMenuItem();
    private ToolStripRadioButtonMenuItem toolStripRadioButtonMenuItem6 = 
        new ToolStripRadioButtonMenuItem();

    public Form1()
    {
        mainToolStripMenuItem.Text = "main";
        toolStripRadioButtonMenuItem1.Text = "option 1";
        toolStripRadioButtonMenuItem2.Text = "option 2";
        toolStripRadioButtonMenuItem3.Text = "option 2-1";
        toolStripRadioButtonMenuItem4.Text = "option 2-2";
        toolStripRadioButtonMenuItem5.Text = "option 3-1";
        toolStripRadioButtonMenuItem6.Text = "option 3-2";
        toolStripMenuItem1.Text = "toggle";
        toolStripMenuItem1.CheckOnClick = true;

        mainToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] {
            toolStripRadioButtonMenuItem1, toolStripRadioButtonMenuItem2,
            toolStripMenuItem1});
        toolStripRadioButtonMenuItem2.DropDownItems.AddRange(
            new ToolStripItem[] {toolStripRadioButtonMenuItem3, 
            toolStripRadioButtonMenuItem4});
        toolStripMenuItem1.DropDownItems.AddRange(new ToolStripItem[] {
            toolStripRadioButtonMenuItem5, toolStripRadioButtonMenuItem6});

        menuStrip1.Items.AddRange(new ToolStripItem[] {mainToolStripMenuItem});
        Controls.Add(menuStrip1);
        MainMenuStrip = menuStrip1;
        Text = "ToolStripRadioButtonMenuItem demo";
    }
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

Компиляция кода

Для этого примера требуются перечисленные ниже компоненты.

  • Ссылки на сборки System, System.Drawing и System.Windows.Forms.

См. также

Задачи

Практическое руководство. Реализация пользовательского класса, производного от ToolStripRenderer

Ссылки

MenuStrip

ToolStripMenuItem

ToolStripMenuItem.CheckOnClick

ToolStripMenuItem.Checked

ToolStripMenuItem.OnCheckedChanged

ToolStripMenuItem.OnPaint

ToolStripMenuItem.Enabled

RadioButtonRenderer

Другие ресурсы

Элемент управления MenuStrip (Windows Forms)