WPF Мастер: Как сделать кнопку “Далее” серой, когда ни одна радиокнопка еще не выбрана

Вопрос или проблема

Я хочу, чтобы кнопка «Далее» в мастере была доступна только после выбора радиокнопки.

<Window x:Class="WpfWizard.WizardWindow"
        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:local="clr-namespace:WpfWizard"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        mc:Ignorable="d"
        Title="WizardWindow" Height="450" Width="800">
    <Grid>
        <xctk:Wizard FinishButtonClosesWindow="True">
            <xctk:WizardPage x:Name="IntroPage" 
                             Title="Добро пожаловать в мой мастер"
                             Description="Этот мастер проведет вас через процесс выполнения чего-либо.">
                <Grid>
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <RadioButton GroupName="ServerSelection" Margin="20">Старая серверная среда</RadioButton>
                            <RadioButton GroupName="ServerSelection" Margin="20">Новая серверная среда</RadioButton>
                        </StackPanel>
                    </StackPanel>
                </Grid>
            </xctk:WizardPage>
            <xctk:WizardPage x:Name="Page1" PageType="Interior"
                             Title="Страница 1"
                             Description="Это первая страница в процессе."
                             NextPage="{Binding ElementName=Page2}"
                             PreviousPage="{Binding ElementName=IntroPage}">
                             
            </xctk:WizardPage>
            <xctk:WizardPage x:Name="Page2" PageType="Interior"
                             Title="Страница 2"
                             Description="Это вторая страница в процессе">
            </xctk:WizardPage>

            <xctk:WizardPage x:Name="LastPage" PageType="Interior"
                             Title="Последняя страница"
                             Description="Это последняя страница в процессе"
                             CanFinish="True">
            </xctk:WizardPage>
        </xctk:Wizard>
    </Grid>
</Window>

Я пытался реализовать решение из этого вопроса, однако не могу использовать атрибут Page внутри WizardPage, поэтому это не совсем работает для меня.

Ответ или решение

Чтобы сделать кнопку "Далее" в вашем мастере WPF недоступной до тех пор, пока не будет выбрана одна из радиокнопок, мы можем использовать привязку данных и триггеры. В этой инструкции я пошагово опишу, как это сделать, основываясь на вашей структуре XAML.

1. Подготовка модели данных

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

using System.ComponentModel;

public partial class WizardWindow : Window, INotifyPropertyChanged
{
    private bool _isRadioButtonSelected;

    public bool IsRadioButtonSelected
    {
        get => _isRadioButtonSelected;
        set
        {
            if (_isRadioButtonSelected != value)
            {
                _isRadioButtonSelected = value;
                OnPropertyChanged(nameof(IsRadioButtonSelected));
                OnPropertyChanged(nameof(NextButtonEnabled));
            }
        }
    }

    public bool NextButtonEnabled => IsRadioButtonSelected;

    public WizardWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. Настройка XAML

Теперь мы можем настроить XAML, чтобы использовать привязку к свойству NextButtonEnabled. Измените определение вашей кнопки "Далее" в WizardWindow.xaml следующим образом:

<xctk:Wizard FinishButtonClosesWindow="True">
    <xctk:WizardPage x:Name="IntroPage" 
                     Title="Welcome to my Wizard"
                     Description="This Wizard will walk you through how to do something.">
        <Grid>
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <RadioButton GroupName="ServerSelection" Margin="20"
                                 Checked="RadioButton_Checked"
                                 Unchecked="RadioButton_Unchecked">Старое серверное окружение</RadioButton>
                    <RadioButton GroupName="ServerSelection" Margin="20"
                                 Checked="RadioButton_Checked"
                                 Unchecked="RadioButton_Unchecked">Новое серверное окружение</RadioButton>
                </StackPanel>
            </StackPanel>
        </Grid>
    </xctk:WizardPage>

    <!-- Другие страницы мастера -->

    <xctk:WizardPage x:Name="Page1" PageType="Interior"
                     Title="Page 1"
                     Description="This is the first page in the process."
                     NextPage="{Binding ElementName=Page2}"
                     PreviousPage="{Binding ElementName=IntroPage}">
        <xctk:WizardButton x:Name="NextButton" IsEnabled="{Binding NextButtonEnabled}" />
    </xctk:WizardPage>
</xctk:Wizard>

3. Реакция на выбор радиокнопки

Обработайте события Checked и Unchecked для радиокнопок, добавив следующие методы в ваш класс WizardWindow:

private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
    IsRadioButtonSelected = true;
}

private void RadioButton_Unchecked(object sender, RoutedEventArgs e)
{
    // Проверяем, осталась ли хотя бы одна радиокнопка выбранной
    var anyChecked = ServerSelection.Children.OfType<RadioButton>().Any(r => r.IsChecked == true);
    IsRadioButtonSelected = anyChecked;
}

Заключение

Теперь кнопка "Далее" станет доступной только в том случае, если будет выбрана одна из радиокнопок на первой странице мастера. Используйте клиники и триггеры для управления доступностью элементов интерфейса в соответствии с состоянием ваших данных, следуя принципам MVVM, которые позволяют разделить логику приложения и отображение интерфейса, что делает ваш код более чистым и поддерживаемым.

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

Оцените материал
Добавить комментарий

Капча загружается...