.NET Frameworkフォームのメニュー項目にラジオボタンをふるまわさせる（LINQ使用）

#はじめに
フォームのメニューで、ラジオボタン（オプションボタン）的な「排他的チェックマーク付け機能」を簡単に実装をしてみます。チェックボックス的な仕組みは標準で搭載されているのですが...

![image.png](https://qiita-image-store.s3.amazonaws.com/0/100206/2c37035c-950b-1385-cfaf-ebdd40059cd6.png)

#コードと説明
.NET Framework 4.5.2 で、「Windows フォームアプリケーション」プロジェクトを作成しています。

```C#:Form1.cs
using System;
using System.Linq;
using System.Windows.Forms;

namespace SampleApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //  初期設定（チェックマークをつけておきます）
            //  フォームデザイナでプロパティ指定してもよいです。
            ToolStripMenuItemViewFontSizeMedium.CheckState = CheckState.Indeterminate;
            ToolStripMenuItemViewFontNonBold.CheckState = CheckState.Indeterminate;
        }

        private void ToolStripMenuItemViewFontSizeLarge_Click(object sender, EventArgs e)
        {
            CheckToolStripMenuItemAsRadioItem(sender);
        }

        private void ToolStripMenuItemViewFontSizeMedium_Click(object sender, EventArgs e)
        {
            CheckToolStripMenuItemAsRadioItem(sender);
        }

        private void ToolStripMenuItemViewFontSizeSmall_Click(object sender, EventArgs e)
        {
            CheckToolStripMenuItemAsRadioItem(sender);
        }

        private void ToolStripMenuItemViewFontSizeExtraSmall_Click(object sender, EventArgs e)
        {
            CheckToolStripMenuItemAsRadioItem(sender);
        }

        /// <summary>
        /// クリックされたメニュー項目を、同位置にあるメニュー項目をグループとするのラジオボタンとしてチェックします。
        /// </summary>
        /// <param name="clickedItem"></param>
        private void CheckToolStripMenuItemAsRadioItem(object clickedItem)
        {
            //  選択されたメニュー項目
            var thisItem = clickedItem as System.Windows.Forms.ToolStripMenuItem;
            if (thisItem == null)
                return;

            //  その親項目
            var containerItem = thisItem.GetCurrentParent();

            //  (Linqを使った例）
            //  その子項目をToolStripMenuItem型のみ（つまりセパレータなどは除外して）列挙を行い
            //  選択された項目であればIntermediate、それ以外はUncheckedを、CheckStateプロパティに設定します。

            //  2018-10-20 All()使用でリソース消費を抑えています - albireoさんのコメントより
            containerItem.Items.OfType<System.Windows.Forms.ToolStripMenuItem>()
                .All(f => { f.CheckState = (f == thisItem) ? CheckState.Indeterminate : CheckState.Unchecked; return true; });
            //  もとはこちら
            //  containerItem.Items.OfType<System.Windows.Forms.ToolStripMenuItem>().ToList()
            //    .ForEach(f => f.CheckState = (f == thisItem) ? CheckState.Indeterminate : CheckState.Unchecked);
        }
    }
}

```

CheckToolStripMenuItemAsRadioItem という名のメソッドに集約して、メニューにラジオボタン的ふるまいをさせています。コメントなどを除けば、実質1行にまとめられる内容です。

自分の親の子たちは自分と兄弟姉妹、ということで、「親の子たち」をラジオボタングループのメンバーとみなし、LINQ を使って列挙してチェックマークを設定しています。

対象のメニュー項目をクリックされたイベントハンドラから、前述のこのメソッドを呼び出しています。
クリックされたメニュー項目の「親の子たち」から、 Enumerable.[OfType<T>()](https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.oftype) メソッドでメニュー項目である [ToolStripMenuItem](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.toolstripmenuitem) 型のもののみ（つまりセパレータなどは除かれます）を列挙し、クリックされた項目であれば [CheckState.Intermediate](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.checkstate) 、そうでなければ CheckState.Unchecked を [CheckState](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.toolstripmenuitem.checkstate) プロパティに設定しています。
列挙後の各要素（＝メニュー項目）へのプロパティ設定操作は、LINQ の [All](https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.all)メソッドによる評価式内で行わせています（albireoさんのコメントにより改善してみました）

#おわりに
LINQ は本当に便利ですね！
あと、ToolStripMenuItem.CheckState プロパティに CheckState.Intermediate を指定して表示される丸点は本来ラジオボタンの選択マークではないのですが、似ているので使ってみています。従来からのWindowsフォームのメニュー項目向けには、[CheckMenuRadioItem](https://msdn.microsoft.com/ja-jp/library/cc410707.aspx) という、純正ラジオマークを付与する Win32API が用意されているのですよね。。