Триггер XAML для переменной с тремя состояниями в MVVM

У меня есть bool? в моем ViewModel, который связывается с двумя RadioButtons в моем XAML.

Я бы хотел, чтобы для первого RadioButton'sIsChecked было установлено значение True, если свойство равно true или null, а для второго RadioButton было установлено значение, обратное этому. Я просто не могу найти способ заставить это работать при обновлении свойства в ViewModel.

Вот мой текущий XAML, который на самом деле не работает:

<RadioButton Name = "RadioButtonDhcpConfig" Grid.Row = "1" Grid.Column = "1" Content = "DHCP" VerticalAlignment = "Center" Margin = "5">
    <RadioButton.Resources>
        <Style TargetType = "RadioButton">
            <Setter Property = "IsChecked" Value = "{Binding DhcpEnabled}"/>
            <Style.Triggers>
                <DataTrigger Binding = "{Binding DhcpEnabled}" Value = "{x:Null}">
                    <Setter Property = "IsChecked" Value = "True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </RadioButton.Resources>
</RadioButton>
<!--Row 2-->
<RadioButton Name = "RadioButtonManualConfiguration"  Grid.Row = "2" Grid.Column = "1" Content = "Manual Configuration:" VerticalAlignment = "Center" Margin = "5">
    <RadioButton.Resources>
        <Style TargetType = "RadioButton">
            <Setter Property = "IsChecked" Value = "{Binding DhcpEnabled}"></Setter>
            <Style.Triggers>
                <DataTrigger Binding = "{Binding DhcpEnabled}" Value = "False">
                    <Setter Property = "IsChecked" Value = "True"></Setter>
                </DataTrigger>
                <DataTrigger Binding = "{Binding DhcpEnabled}" Value = "{x:Null}">
                    <Setter Property = "IsChecked" Value = "False"></Setter>
                </DataTrigger>
                <DataTrigger Binding = "{Binding DhcpEnabled}" Value = "True">
                    <Setter Property = "IsChecked" Value = "False"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </RadioButton.Resources>
</RadioButton>

Если я удалю все DataTriggers из второго RadioButton, установщик для DhcpEnabled вызывается при щелчке по первому RadioButton (как и ожидалось), но XAML над установщиком никогда не вызывается.

Проблема здесь в том, что мне нужно убедиться, что для моего свойства DhcpEnabled установлено значение false, когда пользователь щелкает второй RadioButton и не может найти способ сделать это.

Любая помощь будет оценена.

Вы думали о том, чтобы добавить эту логику в модель просмотра? Думаю, было бы более читабельно.

Andy 18.12.2018 12:38

@ Энди, разве для этого не потребовалось бы, чтобы я получил два разных свойства, по одному на RadioButton? Что в конечном итоге также означало бы дополнительный код, чтобы гарантировать, что не существует сценария, в котором они либо ложны, либо оба истинны (хотя оба значения null в порядке).

cogumel0 18.12.2018 12:41

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

XAMlMAX 18.12.2018 12:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
72
3

Ответы 3

Вот конвертер для вашей первой кнопки:

public class Bool2NullConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return value == null;
        }
        if (value is bool?)
        {
            return (value as bool?).Value;
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}  

Затем вы могли бы использовать это в своем RadioButton следующим образом:
<RadioButton IsChecked = "{Binding DhcpEnabled, Converter = {StaticResource bool2Null}}">
Все, что вам нужно сделать сейчас, это изменить логику первого преобразователя, чтобы он стал инвертором, и применить его ко второму RadioButton. Это также сделает XAML намного чище.

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

<RadioButton Name = "RadioButtonDhcpConfig" Grid.Row = "1" Grid.Column = "1" Content = "DHCP" VerticalAlignment = "Center" Margin = "5">
    <RadioButton.Style>
        <Style TargetType = "RadioButton">
            <Setter Property = "IsChecked" Value = "True"/>
            <Style.Triggers>
                <DataTrigger Binding = "{Binding DhcpEnabled}" Value = "False">
                    <Setter Property = "IsChecked" Value = "False"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </RadioButton.Style>
</RadioButton>
<!--Row 2-->
<RadioButton Name = "RadioButtonManualConfiguration"  Grid.Row = "2" Grid.Column = "1" Content = "Manual Configuration:" VerticalAlignment = "Center" Margin = "5">
    <RadioButton.Style>
        <Style TargetType = "RadioButton">
            <Setter Property = "IsChecked" Value = "False"/>
            <Style.Triggers>
                <DataTrigger Binding = "{Binding ElementName=RadioButtonDhcpConfig, Path=IsChecked}" Value = "False">
                    <Setter Property = "IsChecked" Value = "True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </RadioButton.Style>
</RadioButton>

Это не вызывает установщика DhcpEnabled, который требуется.

cogumel0 18.12.2018 13:24

Добавьте инвертированное свойство в модель просмотра (или используйте конвертер):

private bool? dhcpEnabled;

public bool? DhcpEnabled
{
    get => dhcpEnabled;
    set
    {
        if (dhcpEnabled != value)
        {
            dhcpEnabled = value;
            OnPropertyChanged(nameof(DhcpEnabled));
            OnPropertyChanged(nameof(DhcpDisabled));
        }
    }
}

public bool? DhcpDisabled
{
    get => DhcpEnabled == false;
    set => DhcpEnabled = !value;
}

Затем в XAML:

Обратите особое внимание на атрибут GroupName.

<RadioButton x:Name = "RadioButtonDhcpConfig"
             GroupName = "MyDhcp"
             Grid.Row = "1" Grid.Column = "1" Content = "DHCP"
             VerticalAlignment = "Center" Margin = "5"
             IsChecked = "{Binding DhcpEnabled}"/>
<RadioButton x:Name = "RadioButtonManualConfiguration"
             GroupName = "MyDhcp"
             Grid.Row = "2" Grid.Column = "1"
             Content = "Manual Configuration:"
             VerticalAlignment = "Center" Margin = "5"
             IsChecked = "{Binding DhcpDisabled}"/>

Это не вызывает установщика DhcpEnabled

cogumel0 18.12.2018 13:25

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

l33t 18.12.2018 13:50

На самом деле это все еще не работает. По несколько другой причине. DhcpDisabled - это свойство SelectedNetworkAdapter, которое пользователь может изменить. Радиокнопки обернуты вокруг Grid, а его DataContext установлен на SelectedNetworkAdapter. Однако это означает, что если для DhcpDisabled установлено значение True, и я заменю SelectedNetworkAdapter на что-то другое, у которого есть DhcpDisabled как False, будет вызван получатель DhcpDisabled, изменится IsSelected из RadioButtonManualConfiguration, а вместе с ним будет вызван установщик DhcpDisabled. снова.

cogumel0 18.12.2018 15:48

Другими словами, это будет означать, что он будет называть DhcpEnabled = !value, а value - это false, поэтому он установит DhcpEnabled обратно на true.

cogumel0 18.12.2018 15:49

Если кнопки находятся в группе, то кнопка disable ни к чему не должна быть привязана. Он просто сбросит первый, который автоматически установит для него значение false.

XAMlMAX 19.12.2018 01:07

Другие вопросы по теме