WPF Как из одного UserControl перейти в другой UserControl по нажатию на кнопку на первом

Как в главной форме по нажатию кнопки в первом UserControl отрылся 2 UserControl, а первый закрылся. Пытаюсь решить эту простую задачу уже 2 день. Можно показать пример, как реализовать эту задачу.


Ответы (1 шт):

Автор решения: aepot

UserControl в плане Visibility ничем не отличается от любого другого контрола, так как у них общий родитель UIElement.

Следовательно можно вопрос поставить так: При нажатии кнопки один TextBox должен прятаться, а второй появляться на его месте.

Создаем класс, реализующий интерфейс INotifyPropertyChanged, далее от него можно наследовать любой другой класс для работы с свойствами, умеющими обновлять интерфейс.

public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

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

public class MainViewModel : NotifyPropertyChanged
{
    private bool _visibleState;

    public bool VisibleState
    {
        get => _visibleState;
        set
        {
            _visibleState = value;
            OnPropertyChanged(); // сообщает привязанным сюда биндингам, что свойство поменялось.
        }
    }
}

VisibleState как раз и будет отвечать за то, какой из текстбоксов будет показан.

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

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
    public void Execute(object parameter) => _execute(parameter);
}

И доработаю MainViewModel, создам команду, которая будет менять VisibleState.

public class MainViewModel : NotifyPropertyChanged
{
    private bool _visibleState;
    private ICommand _changeVisibleStateCommand;

    public bool VisibleState
    {
        get => _visibleState;
        set
        {
            _visibleState = value;
            OnPropertyChanged();
        }
    }

    public ICommand ChangeVisibleStateCommand =>
        _changeVisibleStateCommand ?? (_changeVisibleStateCommand = new RelayCommand(parameter => 
        {
            VisibleState = !VisibleState;
        }));
}

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

public MainWindow()
{
    InitializeComponent();
    DataContext = new MainViewModel();
}

Отлично, теперь можно использовать привязки Binding.

Вот полная разметка.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Button Margin="5" Content="Click me!" HorizontalAlignment="Left" Command="{Binding CangeVisibleStateCommand}"/>
            <TextBox Margin="5" Text="1st TextBox">
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding VisibleState}" Value="True">
                                <Setter Property="Visibility" Value="Collapsed"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>
            <TextBox Margin="5" Text="2nd TextBox">
                <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                        <Setter Property="Visibility" Value="Collapsed"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding VisibleState}" Value="True">
                                <Setter Property="Visibility" Value="Visible"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>
        </StackPanel>
    </Grid>
</Window>

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

С UserControl все в точности то же самое, как и с любым другим контролом.

→ Ссылка