Поскольку самамильного ответа нет, я выкладываю свое решение здесь:
public class RadioMenuItem : MenuItem
{
public string GroupName { get; set; }
protected override void OnClick()
{
var ic = Parent as ItemsControl;
if (null != ic)
{
var rmi = ic.Items.OfType<RadioMenuItem>().FirstOrDefault(i =>
i.GroupName == GroupName && i.IsChecked);
if (null != rmi) rmi.IsChecked = false;
IsChecked = true;
}
base.OnClick();
}
}
В XAML просто используйте его как обычный MenuItem:
<MenuItem Header="OOO">
<local:RadioMenuItem Header="111" GroupName="G1"/>
<local:RadioMenuItem Header="222" GroupName="G1"/>
<local:RadioMenuItem Header="333" GroupName="G1"/>
<local:RadioMenuItem Header="444" GroupName="G1"/>
<local:RadioMenuItem Header="555" GroupName="G1"/>
<local:RadioMenuItem Header="666" GroupName="G1"/>
<Separator/>
<local:RadioMenuItem Header="111" GroupName="G2"/>
<local:RadioMenuItem Header="222" GroupName="G2"/>
<local:RadioMenuItem Header="333" GroupName="G2"/>
<local:RadioMenuItem Header="444" GroupName="G2"/>
<local:RadioMenuItem Header="555" GroupName="G2"/>
<local:RadioMenuItem Header="666" GroupName="G2"/>
</MenuItem>
Довольно просто и чисто.И, конечно, вы можете сделать GroupName
свойством зависимости с помощью некоторых дополнительных кодов, это то же самое, что и другие.
Кстати, если вам не нравится флажок, вы можете изменить его на любой другой:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var p = GetTemplateChild("Glyph") as Path;
if (null == p) return;
var x = p.Width/2;
var y = p.Height/2;
var r = Math.Min(x, y) - 1;
var e = new EllipseGeometry(new Point(x,y), r, r);
// this is just a flattened dot, of course you can draw
// something else, e.g. a star? ;)
p.Data = e.GetFlattenedPathGeometry();
}
Если вы много использовали этого RadioMenuItem
в своей программе, ниже приведена еще одна более эффективная версия.Литеральные данные взяты из e.GetFlattenedPathGeometry().ToString()
в предыдущем фрагменте кода.
private static readonly Geometry RadioDot = Geometry.Parse("M9,5.5L8.7,7.1 7.8,8.3 6.6,9.2L5,9.5L3.4,9.2 2.2,8.3 1.3,7.1L1,5.5L1.3,3.9 2.2,2.7 3.4,1.8L5,1.5L6.6,1.8 7.8,2.7 8.7,3.9L9,5.5z");
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var p = GetTemplateChild("Glyph") as Path;
if (null == p) return;
p.Data = RadioDot;
}
И наконец, если вы планируете обернуть их для использования в своем проекте, вы должны скрыть свойство IsCheckable
из базового класса., поскольку механизм автоматической проверки класса MenuItem
приведет к неправильному поведению состояния проверки радио.
private new bool IsCheckable { get; }
Таким образом, VS выдаст ошибку, если новичок попытается скомпилировать XAML следующим образом:
// обратите внимание, что это неправильное использование!
<local:RadioMenuItem Header="111" GroupName="G1" IsCheckable="True"/>
// обратите внимание, что это неправильное использование!