, , VM .
Here is my solution: an attached property that toggles the IsChecked property of all buttons in the same group. Works on my car :-)
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace Elca.MvvmHelpers {
public class RadioButtonHelper : DependencyObject {
private static readonly Dictionary<string, List<RadioButton>> s_group2ButtonsMap = new Dictionary<string, List<RadioButton>>();
private static readonly List<RadioButton> s_knownButtons = new List<RadioButton>();
private static void OnRadioButtonChecked(object sender, RoutedEventArgs e) {
RadioButton rb = (RadioButton)sender;
UncheckOtherButtonsInGroup(rb);
}
public static bool? GetIsChecked(RadioButton d) {
return (bool?) d.GetValue(IsCheckedProperty);
}
public static void SetIsChecked(RadioButton d, bool? value) {
d.SetValue(IsCheckedProperty, value);
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked",
typeof(bool?),
typeof(RadioButtonHelper),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal |
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
IsCheckedChanged));
public static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var rb = d as RadioButton;
if (rb == null) {
throw new Exception("IsChecked attached property only works on a FrameworkElement type");
}
RememberRadioButton(rb);
if ((bool) e.NewValue) {
rb.IsChecked = true;
}
}
private static void RememberRadioButton(RadioButton rb) {
var groupName = GetGroupName(rb);
if (s_knownButtons.Contains(rb)) {
return;
}
s_knownButtons.Add(rb);
List<RadioButton> existingButtons;
if (! s_group2ButtonsMap.TryGetValue(groupName, out existingButtons)) {
s_group2ButtonsMap[groupName] = new List<RadioButton> {rb};
RegisterButtonEvents(rb);
} else {
if (! existingButtons.Contains(rb)) {
existingButtons.Add(rb);
RegisterButtonEvents(rb);
}
}
}
private static void RegisterButtonEvents(RadioButton rb) {
rb.Unloaded += OnButtonUnloaded;
rb.Checked += OnRadioButtonChecked;
}
private static void OnButtonUnloaded(object sender, RoutedEventArgs e) {
RadioButton rb = (RadioButton) sender;
ForgetRadioButton(rb);
}
private static void ForgetRadioButton(RadioButton rb) {
List<RadioButton> existingButtons = s_group2ButtonsMap[GetGroupName(rb)];
existingButtons.Remove(rb);
s_knownButtons.Remove(rb);
UnregisterButtonEvents(rb);
}
private static void UnregisterButtonEvents(RadioButton rb) {
rb.Unloaded -= OnButtonUnloaded;
rb.Checked -= OnRadioButtonChecked;
}
private static void UncheckOtherButtonsInGroup(RadioButton rb) {
List<RadioButton> existingButtons = s_group2ButtonsMap[GetGroupName(rb)];
foreach (RadioButton other in existingButtons) {
if (other != rb) {
SetIsChecked(other, false);
}
}
SetIsChecked(rb, true);
}
private static string GetGroupName(RadioButton elt) {
string groupName = elt.GroupName;
if (String.IsNullOrEmpty(groupName)) {
groupName = "none";
}
return groupName;
}
}
}
In the view for each button:
<RadioButton MvvmHelpers:RadioButtonHelper.IsChecked="{Binding IsExplicitFileSelected, Mode=TwoWay}">
...
</RadioButton>
The VM has a logical property for each switch. Each such property is assigned a value to begin the process of listening to the attached property.
All buttons without a group name are considered part of the same group.
source
share