Как установить правильное свойство RadioButton.IsChecked True путем привязки к ViewModel? - PullRequest
2 голосов
/ 07 июня 2011

У меня есть следующий сценарий, где класс подобен этому:

public class PetOwnerViewModel{
public PetOwnerStatus Status{get{return _petOwner.Status;}}

    public ICommand SetStatusCommand {get{...}}
}

Является ли DataContext для группы переключателей RadioButton похожей на эту:

<Parent DataContext="{Binding Path=PetOwner}" >
    <Parent.Resources>
        <myenums:PetOwnerStatus x:Key="CATLOVER">
            CatLover
        </myenums:PetOwnerStatus>
        <myenums:PetOwnerStatus x:Key="DOGLOVER">
            DogLover
        </myenums:PetOwnerStatus>
    </Parent.Resources>     
<StackPanel>
        <RadioButton Name="catLoverRadioButton"
                    Command="{Binding SetStatusCommand}"  
                CommandParameter="{StaticResource DOGLOVER}"
        GroupName="PetOwnerStatusRadioButtonGroup">
            Cat Lover
    </RadioButton>
        <RadioButton Name="dogLoverRadioButton"
                    Command="{Binding SetStatusCommand}"
                    CommandParameter="{StaticResource CATLOVER}"
        GroupName="SubjectStatusRadioButtonGroup" >
            Dog Lover
        </RadioButton>
    </StackPanel>
</Parent>

Как связать представление сViewModel, так что если PetOwnerViewModel.Status возвращает PetOwnerStatus.CatLover, catLoverRadioButton.IsChecked имеет значение true.

Ответы [ 2 ]

3 голосов
/ 07 июня 2011

Вы можете сделать такие вещи очень динамичными, используя шаблонизацию данных, например,

(- Редактировать: Имеет гораздо больше смысла использовать ListBoxу которого уже есть свойство SelectedItem, см. этот исправленный ответ -)

public partial class MainWindow : Window, INotifyPropertyChanged
{
    //For simplicity in put everything in the Window rather than models and view-models
    public enum TestEnum { Ichi, Ni, San }

    private TestEnum _EnumValue;
    public TestEnum EnumValue
    {
        get { return _EnumValue; }
        set
        {
            if (_EnumValue != value)
            {
                _EnumValue = value;
                PropertyChanged.Notify(() => this.EnumValue);
            }
        }
    }

    //...
}
<ItemsControl>
    <ItemsControl.Resources>
        <!-- Gets the enum values -->
        <ObjectDataProvider x:Key="items" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:MainWindow+TestEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        <!-- A MultiValueConverter which compares for equality -->
        <vc:EqualityComparisonConverter x:Key="eqc" />
    </ItemsControl.Resources>
    <ItemsControl.ItemsSource>
        <Binding Source="{StaticResource items}" />
    </ItemsControl.ItemsSource>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <RadioButton Content="{Binding}" GroupName="TestEnumGroup"
                    Command="{x:Static local:Commands.DoStuff}" CommandParameter="{Binding}">
                <RadioButton.IsChecked>
                    <MultiBinding Converter="{StaticResource eqc}" Mode="OneWay">
                        <!-- This should point to the viewmodel enum property -->
                        <Binding ElementName="Window" Path="DataContext.EnumValue" />
                        <!-- This passes the DataContext, the enum value behind the templated item, to the converter -->
                        <Binding />
                    </MultiBinding>
                </RadioButton.IsChecked>
            </RadioButton>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
private void DoStuff_Executed(object sender, ExecutedRoutedEventArgs e)
{
    TestEnum enumval = (TestEnum)e.Parameter;
    EnumValue = enumval;
}

Это работает с необработанными значениями enum, вы можетедополните их отображаемыми строками, используя атрибуты.

Поскольку IsChecked привязан ко всем RadioButton, RadioButton.GroupName становится избыточным.

( Я не предоставил свою реализацию EqualityComparisonConverter поскольку это, вероятно, дерьмо, не должно быть слишком сложно правильно его реализовать, хотя )

2 голосов
/ 11 июня 2011

В WPF есть довольно известная ошибка с привязкой данных и RadioButton.Вот как я обычно это делаю:

<StackPanel>
    <RadioButton
        Content="Cat Lover"
        Command="{Binding SetStatusCommand}"  
        CommandParameter="{x:Static local:PetOwnerStatus.CatLover}"
        IsChecked="{Binding Path=Status, Mode=TwoWay, Converter={StaticResource equalityConverter}, ConverterParameter={x:Static local:PetOwnerStatus.CatLover}}"
        GroupName="1" />

    <RadioButton
        Content="Dog Lover"
        Command="{Binding SetStatusCommand}"  
        CommandParameter="{x:Static local:PetOwnerStatus.DogLover}"
        IsChecked="{Binding Path=Status, Mode=TwoWay, Converter={StaticResource equalityConverter}, ConverterParameter={x:Static local:PetOwnerStatus.DogLover}}"
        GroupName="2" />
</StackPanel>

. EquleConverter принимает параметр ConverterParameter для перечисления и сравнивает его со значением привязки (Status).Если значения равны, преобразователь возвращает значение true, которое, в свою очередь, устанавливает значение IsChecked в значение true.Вышеприведенное выражение привязки IsChecked фактически говорит: «Если значение, указанное в ConverterParameter, равно значению Status, установите IsChecked в true».

Кроме того, вы можете использовать фактические значения перечисления, определив пространство имен и используя x:Статический, без необходимости создавать отдельные ресурсы.

Обратите внимание, что вы должны назначить разные имена групп каждому RadioButton, в противном случае ошибка WPF проявляется и привязки нарушаются.

Более подробная информация доступназдесь: Как привязать RadioButtons к перечислению?

...