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?
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();
}
}
```