W jaki sposób podmienić kontrolki w widoku okna głównego?

0

jak uzyskac dostep do currentview w modelu widoku okna glownego aby usercontrol1 mogl podmienic kontrolke na usercontrol2 w oknie glownym. czy to do bry kurs czy zmienic sposob roziazania na inny... jaki?

Diagram bez tytułu.drawio.png

1

Może się komuś przydać także wklejam działające rozwiązanie, sam też skorzystam jeżeli ktoś poprawi mój kod i opis do niego.

Starałem się żeby było zgodne z MVVM, użyłem klasy RelayCommand, która przewija się we wszystkich tutorialach pod tą nazwą lub innymi np. DelegateCommand, MVVMCommand itp.

Opis:
IMainView - hermetyzuje dostęp do okna głównego z poziomu UserControlViewModel do których jest przekazywane przez parametr w konstruktorze.
IUserControlViewModel - wprowadza abstrakcje dla zmienianych usercontrol w widoku głównym, w tym przypadku daje dostęp do jednej właściwości podmienianych kontrolek i wystawia je na widoku głównym
ViewModelBase - implementuje INotifyPropertyChanged i jest to klasa bazowa dla wszystkich ViewModeli okien i usercontrol w aplikacji
MainWindow.xaml - widok okna głównego, sekcja Window.Resources ustawia/definiuje sposób wyświetlania podmienianych w ContentControl kontrolek użytkownika, dzięki tej sekcji następuje wiązanie, który usercontrol będzie korzystał z którego viewmodelu.
MainWindowViewModel - viewmodel sterujący oknem głównym, definiuje metody lądujące dwa rodzaje usercontrol 1 i 2, jedna metoda 'UstawUserControl1()' jest wywoływana w konstruktorze aby ustawić ta kontrolkę po uruchomieniu aplikacji, i ta metoda jest wiązana z poleceniem które będzie ustawiało 'spod przycisku' usercontrol1 w widoku głównym - ale przycisk do którego wiązane jest to polecenie będzie aktywny tylko wtedy gdy aktualnie załadowana kontrolka będzie cos innego niż usercontrol1, patrz definicja polecenia w konstruktorze MainWindowViewModel
UserControl2_View.xaml oraz UserControl2ViewModel - odpowiednio widok i sterujący nim viewmodel, nic się w nim nie dzieje, jest tworzony w oknie głównym za pomocą konstruktora bezparametrowego, nie przekazywana jest do niego referencja okna głównego ponieważ nie używa jej.
UserControl1_View.xaml oraz UserControl1ViewModel - odpowiednio widok i sterujący nim viewmodel, jest tworzony w oknie głównym, do jego konstruktora przekazywana jest referencja okna głównego i to na tej referencji wywołuje w sobie metodę ładowania kontrolki użytkownika 2 na widoku głównym. Tutaj pomimo tego ze wykorzystuje się do utworzenia tego obiektu w viewmodelu okna głównego ,konstruktora z jednym parametrem typu IMainView, to musi on mieć również w sobie zdefiniowany konstruktor bezparametrowy ponieważ takiego konstruktora wymaga XAML w oknie w którym jest definiowany jako DataContext danego okna - inaczej zamiast kontrolki w oknie głównym będzie wyświetlała się tylko pełna nazwa typu załadowanej kontrolki do ContentControl.

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string nazwaWlasciwosci)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(nazwaWlasciwosci));
        }
    }
    
    public interface IMainView
    {
        void UstawUserControl1();
        void UstawUserControl2();
    }
    
    public class MainWindowViewModel : ViewModelBase, IMainView
    {
        public ICommand PrzywrocUserControl1 {get;}

        public string NazwaZaladowanejUserControl => WymiennyUserControl?.NazwaUserControl;

        private IUserControlViewModel wymiennyUserControl;
        public IUserControlViewModel WymiennyUserControl
        {
            get { return wymiennyUserControl; }
            set { wymiennyUserControl = value;
                OnPropertyChanged(nameof(WymiennyUserControl));
                OnPropertyChanged(nameof(NazwaZaladowanejUserControl)); }
        }

        public MainWindowViewModel()
        {
            PrzywrocUserControl1 = new RelayCommand(UstawUserControl1, () => {  return WymiennyUserControl is not UserControl1ViewModel; });

            UstawUserControl1();
        }

        public void UstawUserControl1()
        {
            WymiennyUserControl = new UserControl1ViewModel(this);
        }

        public void UstawUserControl2()
        {
            WymiennyUserControl = new UserControl2ViewModel();
        }
    }
<Window x:Class="WPF_przelaczanie_usercontrol.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:WPF_przelaczanie_usercontrol"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:UserControl1ViewModel}">
            <local:UserControl1_View/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:UserControl2ViewModel}">
            <local:UserControl2_View/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Vertical" 
                   Grid.Row="0"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center">
            <TextBlock Text="Okno głowne" Margin="5"/>
            <Button Content="Przywroc UserControl1" 
                    Command="{Binding PrzywrocUserControl1}"
                    Margin="5"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Nazwa zaladowanej kontrolki: "/>
                <TextBlock Text="{Binding NazwaZaladowanejUserControl}"
                           FontWeight="Bold"/>
            </StackPanel>
        </StackPanel>
        <ContentControl Content="{Binding WymiennyUserControl}"
                        Grid.Row="1"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"/>
    </Grid>
</Window>
    public interface IUserControlViewModel
    {
        string NazwaUserControl { get; }
    }

    public class UserControl1ViewModel : ViewModelBase,IUserControlViewModel
    {
        private IMainView glownyWiok;

        public ICommand ZaladujUserControl2 { get; }

        public string NazwaUserControl => "UserControl z numerkiem 1";

        public UserControl1ViewModel() { }
        public UserControl1ViewModel(IMainView glownyWidok)
        {
            this.glownyWiok = glownyWidok;
            ZaladujUserControl2 = new RelayCommand(ZaladujUserControl_2);
        }

        private void ZaladujUserControl_2()
        {
            glownyWiok.UstawUserControl2();
        }
    }

    public class UserControl2ViewModel : ViewModelBase, IUserControlViewModel
    {
        public string NazwaUserControl => "UserControl z numerkiem 2";
        public UserControl2ViewModel() { }
    }
<UserControl x:Class="WPF_przelaczanie_usercontrol.UserControl1_View"
             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:WPF_przelaczanie_usercontrol"
             mc:Ignorable="d" 
             d:DataContext="{d:DesignInstance Type=local:UserControl1ViewModel}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Rectangle Fill="Beige"/>
        <StackPanel Orientation="Vertical"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center">
            <TextBlock Text="UserControl 1" Margin="5"/>
            <Button Content="Zaladuj UserControl 2"
                    Margin="5"
                    Command="{Binding ZaladujUserControl2}"/>
            <Button Content="Nic"
                    Margin="5"/>
        </StackPanel>
    </Grid>
</UserControl>


<UserControl x:Class="WPF_przelaczanie_usercontrol.UserControl2_View"
             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:WPF_przelaczanie_usercontrol"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Rectangle Fill="AliceBlue"/>
            <TextBlock Text="UserControl 2"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"/>
    </Grid>
</UserControl>

 public class RelayCommand : ICommand
    {
        private readonly Action execute;
        private readonly Func<bool> canExecute;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

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

        public bool CanExecute(object parameter)
        {
            return canExecute == null || canExecute();
        }

        public void Execute(object parameter)
        {
            execute();
        }
    }
    
    ```

1 użytkowników online, w tym zalogowanych: 0, gości: 1