2012-09-22 6 views
0

Я пытаюсь выразить свойство перечисления в моей модели представления как набор переключателей в моем представлении. Все идет нормально; Я могу выразить, что с двухсторонним MultiBinding:Inverted TwoWay-MultiBinding

(rb1.IsChecked, rb2.IsChecked, rb3.IsChecked) < -> vm.Value

Мульти-связывание здесь используемая функция будет мультиконвертер, который преобразует (bool, bool, bool) <-> MyValue; очевидно, одно из (трех) допустимых значений типа MyValue выбрано на основе которого bool является true и наоборот.

Это уже немного неудобно: я не могу определить эту привязку в Xaml моего представления, поскольку множественные привязки должны быть определены со стороны одного значения. Следовательно, я должен определить множественное связывание в кодировке и использовать SetBinding, чтобы установить его на свой вид модели Value.

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

(rbA1.IsChecked, rbA2.IsChecked, rbA3.IsChecked) < -> vm.Value < -> (rbB1.IsChecked, rbB2.IsChecked, rbB3. IsChecked)

проблема заключается в том, что я не могу использовать SetBinding для подключения нескольких привязок vm.Value одновременно.

Решения, которые я пытался до сих пор являются:

  • Используйте один большой мульти-связывание, связывание всех радиокнопок в то время. Это означало бы привязку формы (rbA1.IsChecked, rbA2.IsChecked, rbA3.IsChecked, rbB1.IsChecked, rbB2.IsChecked, rbB3.IsChecked) <-> vm.Value. Проблема с этим решением заключается в том, что если проверяется один из переключателей (скажем, rbB2), я не могу сказать, имеет ли значение rbA2 (непроверенный) или rbB2 (отмечен) «новое, правильное» значение.
  • Прежде всего, группа радиокнопка определит группу радиосвязи, которая предоставляет только один объект SelectedIndex. Это свойство затем может быть удобно привязано к моему свойству vm.Value из всех экземпляров моей группы радиосвязи. Хотя это возможно, для этого требуется написать новый класс управления, и я задаюсь вопросом, является ли это единственным способом в WPF.
  • Bind один набор радиокнопок к другому: по двухстороннему-связывающему rbB1 к rbA1, rbB2 к rbA2, и так далее, и с использованием мульти-связывание между моим vm.Value и первым набор только радио-кнопками, I достигнет желаемого эффекта, но мне не нравится понятие наличия «главной радиогруппы». Было бы злоупотреблять элементами GUI для передачи данных.
  • Выполняйте все действия с кодом и вручную обновляйте переключатели и значение модели представления. Конечно, это жизнеспособное решение для резервного решения, но это чувствует себя, как это должно быть возможно в Xaml/с привязками.
+0

«Использовать один большой многосвязной», я не совсем понял. У вас есть две группы RadioButton. Вы можете выбрать один элемент из группы 1, и вы можете выбрать один элемент из группы 2. Я не понимаю, что «имеет новое правильное значение». –

+0

@ChrisDD: «Большое многосвязывание» свяжет «vm.Value» со всеми шестью переключателями одновременно. Шесть переключателей могут иметь начальное состояние, такое как '(1, 0, 0, 1, 0, 0)'. Предположим, кто-то щелкнул 2-ю радиокнопку во 2-м наборе, поэтому мой мультиконвертер вызывается с помощью '(1, 0, 0, 0, 1, 0)'. Как определить, правильно ли установлен первый набор или второй набор, то есть, нужно ли возвращать первое значение перечисления или второе значение перечисления? Насколько я вижу, это не удобно. –

+0

Почему вы не используете единую привязку для каждого RadioButton? Используйте конвертер и командный параметр. Например: IsChecked = {Binding VMEnum, Converter = {StaticResource toEnum}, ConverterParameter = {YourEnum: FirstButtonChecked}}. Вам необходимо реализовать двухсторонний конвертер. В любом случае IsChecked = VMEnum == (CommandParameter as Enum) [для одного пути] –

ответ

0

Bind VMEnum для каждого RadioButton отдельно (использование одного двухстороннего связывания). Каждая привязка должна иметь CommandParameter, это перечисление. Как:

<RadioButton IsChecked="{Binding VMEnum, Converter={StaticResource EnumConverter}, ConverterParameter={Enums:VMEnums.FirstRadioButtonGroupA}}" /> 

В преобразователе,

  • Преобразовать должен возвращать правильное значение (истина/ложь) в зависимости от VMEnum и CommandParameter. По сути, логика - это VMEnum == (YourEnum) CommandParameter.
  • ConvertBack должен возвращать правильный Enum на основе IsChecked. Если IsChecked истинно, верните правильное перечисление. В противном случае верните Binding.DoNothing, который прервет привязку для этого конкретного случая.
+0

'Binding.DoNothing' была той штукой, которую мне не хватало! –

0

Использование сложного многосвязного преобразования с преобразователями и кодовым кодом не только сделает ваш код сложнее отлаживать, но еще сложнее проверить. На мой взгляд, лучше выразить каждый набор переключателей (флажков) как модель представления. Оцените свою ценность, если какая-либо из переключателей отмечена или снята.

RadioButtonGroup

public class RadioButtonGroup : ViewModel { 

    public RadioButtonGroup(string groupName, int count, Action<bool[]> whenAnyChanaged = null) { 

     RadioButtons = Enumerable.Range(0, count).Select(_ => { 
      var button = new RadioButton { GroupName = groupName }; 
      button.PropertyChanged += (s, e) => { 
       if (e.PropertyName == "IsChecked") 
        whenAnyChanaged(Flags); 
      }; 
      return button; 
     }).ToList();   
    } 

    public List<RadioButton> RadioButtons { get; private set; } 

    public bool[] Flags { get { return RadioButtons.Select(rb => rb.IsChecked).ToArray(); } } 
} 

RadioButton

public class RadioButton : ViewModel { 

    private bool isChecked; 

    public bool IsChecked { 
     get { return isChecked; } 
     set { SetProperty(ref this.isChecked, value); } 
    } 

    public string GroupName { get; set; } 
} 

MainViewModel

public class MainViewModel : ViewModel { 
    public MainViewModel() { 
     GroupA = new RadioButtonGroup("A", 10, flags => GroupToggle(flags, GroupB.Flags)); 
     GroupB = new RadioButtonGroup("B", 10, flags => GroupToggle(GroupA.Flags, flags)); 
    } 

    public RadioButtonGroup GroupA { get; private set; } 

    public RadioButtonGroup GroupB { get; private set; } 

    void GroupToggle(bool[] groupA, bool[] groupB) { 
     MyValue = Evaluate(groupA, groupB); 
    } 
} 

Посмотреть

<Window x:Class="WpfLab.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="{Binding Title}" Height="350" Width="525"> 
<Window.Resources> 
    <DataTemplate x:Key="RadioButton"> 
     <RadioButton IsChecked="{Binding IsChecked, Mode=OneWayToSource}" GroupName="{Binding GroupName}"/> 
    </DataTemplate> 
</Window.Resources> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="30"/> 
     <RowDefinition Height="30"/> 
    </Grid.RowDefinitions> 

    <ListBox Grid.Row="0" ItemsSource="{Binding GroupA.RadioButtons}" ItemTemplate="{StaticResource ResourceKey=RadioButton}"> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 

    <ListBox Grid.Row="1" ItemsSource="{Binding GroupB.RadioButtons}" ItemTemplate="{StaticResource ResourceKey=RadioButton}"> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 
</Grid> 

+0

Что вы используете метод 'Evaluate' в классе' MainViewModel'? В частности, когда состояния «RadioButtonGroup» являются, например, '(1, 0, 0); (0, 1, 0) ', как он знает, является ли' (1, 0, 0) 'или' (0, 1, 0) 'предполагаемым новым состоянием? –

+0

Прямо сейчас это, вероятно, не будет, но вы можете добавить Enum, например, «какая группа была изменена», и добавить его в GroupToggle & modify delegates (MainiewModel()) + передать его Evaluate. –

+0

@ChrisDD: Я думаю, проблема в том, что в то время, когда вызывается 'Evaluate', уже неизвестно/слишком поздно, чтобы узнать, какая группа была изменена. –