2015-04-19 2 views
0

Как вы группируете CheckBoxes (например, RadioButtons могут быть сгруппированы), чтобы, когда кто-то был отмечен, остальные не выбраны?Взаимные эксклюзивные флажки, такие как Grouped RadioButtons

EDIT

Мотивацией для использования CheckBoxes является то, что, по умолчанию, они позволяют пользователю, чтобы отменить их после того, как выбран, в то время как Radiobuttons нет (без дополнительной логики добавил к ним, а). Кроме того, этот тип группировки элементов пользовательского интерфейса более естественным образом сопоставляется с чем-то вроде значения с нулевым значением bool, где есть три допустимых параметра: выбрано, не выбрано, значение null (или вообще нет выбора). Это допустимый прецедент для определенных сценариев. Ни RadioButton, ни CheckBox действительно полностью соответствует этой парадигме.

С точки зрения пользователя, управление для выполнения этого действительно произвольно, поскольку каждый из них представляет собой просто круг, который заполняется, а другой - заполненным квадратом, и вы можете легко визуализировать либо в качестве другого в любом случае, Не думаю, что сбивать с толку кто-то - большая проблема. Я бы сказал, что с меньшей вероятностью будет интересоваться квадрат, на котором ожидался круг, и больше разочаровывается тем, что ему приходится принимать решение между двумя вариантами RadioButton, которые они не хотели выбирать между ними. На самом деле можно было либо создать CheckBoxes, поддерживающие группировку, либо RadioButtons, которые поддерживают отмену выбора, чтобы выполнить это, и этот вопрос касается первого.

+0

Почему вы не используете радиокутоны? Вы только смутите пользователя, используя флажки, которые ведут себя как радиолюбители. Вы также можете создавать текстовые поля, открывающиеся как выпадающие меню при нажатии на них. Но это был бы столь же ужасный выбор UX. –

+0

мой ответ здесь сделал это для меня, простой способ, я могу добавить: http://stackoverflow.com/questions/21135760/mutually-exclusive-radiobuttons-by-row-and-not-by-column-in- GridView/34485366 # 34485366 – Erik

ответ

0

Я так расстроен тем, что вынужден делать это в CodeBehind все время, когда я катал свой собственный класс, который наследует от CheckBox, который добавляет функциональность с тем же API, что и RadioButton. Он пропустил несколько вещей, но здесь он для потомков.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 

namespace GroupedCheckBoxTest 
{ 
    public class GroupedCheckBox : CheckBox 
    { 
     /// <summary> 
     /// All the members of the current group 
     /// </summary> 
     private IEnumerable<GroupedCheckBox> currentGroup; 

     /// <summary> 
     /// Gets or sets the name that specifies which GroupedCheckBox controls are mutually exclusive. 
     /// </summary> 
     public string GroupName { get; set; } 

     /// <summary> 
     /// Indicates when the checked state of the GroupedCheckBox changes 
     /// </summary> 
     public event EventHandler CheckChanged; 

     public GroupedCheckBox() 
     { 
      // Add only the current checkbox to the group 
      // (for now, but potentially always) 
      currentGroup = this.SingleItemAsEnumerable(); 

      // Attach empty delegate so we don't have to keep checking for null 
      this.CheckChanged += delegate { }; 

      // Aggregate all checked changed events 
      this.Checked += GroupedCheckBox_Checked; 

      // Associate all GroupedCheckBoxs once they are loaded 
      this.Loaded += GroupedCheckBox_Loaded; 
     } 

     // False when any one of the group checked 
     void GroupedCheckBox_Checked(object sender, RoutedEventArgs e) 
     { 
      // Uncheck everyone else in the group 
      foreach (GroupedCheckBox otherCB in currentGroup.Except(this.SingleItemAsEnumerable())) 
      { 
       // Uncheck the other checkbox 
       otherCB.IsChecked = false; 
      } 

      this.CheckChanged(this, e); 
     } 

     void GroupedCheckBox_Loaded(object sender, RoutedEventArgs e) 
     { 
      // If this GroupedCheckBox isn't even part of a group 
      if (string.IsNullOrEmpty(this.GroupName)) 
      { 
       // We don't need to do anything special 
       return; 
      } 

      // The highest parent node we can get to 
      DependencyObject parentNode = this; 

      // Walk the control tree until we get to the top 
      while (VisualTreeHelper.GetParent(parentNode) != null) 
      { 
       // Get the parent of the current node 
       parentNode = VisualTreeHelper.GetParent(parentNode); 
      } 

      // Get all GroupedCheckBox's with the same GroupName as this one 
      currentGroup = parentNode.GetControlsOfType<GroupedCheckBox>().Where(cb => this.GroupName == cb.GroupName); 
     } 
    } 

    internal static class GroupedCheckBoxHelperExtensions 
    { 
     public static IEnumerable<T> GetControlsOfType<T>(this DependencyObject depObj) where T : DependencyObject 
     { 
      if (depObj != null) 
      { 
       for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
       { 
        DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
        if (child != null && child is T) 
        { 
         yield return (T)child; 
        } 

        foreach (T childOfChild in GetControlsOfType<T>(child)) 
        { 
         yield return childOfChild; 
        } 
       } 
      } 
     } 

     // usage: someObject.SingleItemAsEnumerable(); 
     public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item) 
     { 
      yield return item; 
     } 
    } 
} 

Просто скопируйте его в GroupedCheckBox.cs и добавить соответствующие ссылки на ваш XAML и использовать его следующим образом:

<UserControl x:Class="UserControl1" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:controls="clr-namespace:YourProject.Controls" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions>   
     <controls:GroupedCheckBox Grid.Row="0" Grid.Column="0" IsChecked="{Binding Path=Stop}" GroupName="1" /> 
     <controls:GroupedCheckBox Grid.Row="0" Grid.Column="1" IsChecked="{Binding Path=Go}" GroupName="1" /> 

     <controls:GroupedCheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding Path=Yes}" GroupName="2" /> 
     <controls:GroupedCheckBox Grid.Row="1" Grid.Column="1" IsChecked="{Binding Path=No}" GroupName="2" /> 
    </Grid> 
</UserControl> 
0

Как в previouse answer, вы можете использовать RadioButton, который маскируется под CheckBox. Или вы делаете логику в коде вашего ViewModel.

Но есть причина, что нет группировки CheckBox: семантика RadioButton заключается в том, что может быть выбран только один из многих. CheckBox сигнализирует пользователю, что ящики не зависят друг от друга.

Поэтому я рекомендую придерживаться RadioButtons, если нет других причин.

Смежные вопросы