Ich bin neu in WPF und XAML und versuche, den Inhalt eines Fensters (Login -> Hauptinhalt und Hauptinhalt -> Login) in einer WindowsApplication (Xaml, WPF) zu ändern. Bisher habe ich im Anschluss an die für diese einfache Login/Logout-Szenario:Change MainWindow Inhalt von ValueConverter
BaseViewModel
public class BaseViewModel : DependencyObject, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
BaseMainViewViewModel (Basisklasse für die Einstellung der MainViewType Liegenschaften in Mainwindow Es enthält auch den Befehl zu ändern. Eigentum über den Button in der MainViews.)
public class BaseMainViewViewModel : BaseViewModel { private static MainViewType _CurrentMainView; private ICommand _SwitchMainViewCommand; public BaseMainViewViewModel() { SwitchMainViewCommand = new RelayCommand(SwitchMainView); } public MainViewType CurrentMainView { get { return _CurrentMainView; } set { if (value != _CurrentMainView) { _CurrentMainView = value; OnPropertyChanged(nameof(CurrentMainView)); } } } public ICommand SwitchMainViewCommand { get { return _SwitchMainViewCommand; } set { _SwitchMainViewCommand = value; } } #region Test public void SwitchMainView(object param) { Debugger.Break(); switch (CurrentMainView) { case MainViewType.Login: CurrentMainView = MainViewType.Main; break; case MainViewType.Main: CurrentMainView = MainViewType.Login; break; default: break; } MessageBox.Show("Login/Logout"); } #endregion Test
LoginViewModel inherites von BaseMainViewViewModel ac zu erhalten Zugang zum Gerät CurrentMainView-Liegenschaften
public class LoginViewModel : BaseMainViewViewModel {}
MainViewModel sie die gleichen
public class MainViewModel : BaseMainViewViewModel {}
MainWindowViewModel
public class MainWindowViewModel: BaseMainViewViewModel {}
LoginMainView
public partial class LoginMainView : UserControl { public LoginMainView() { InitializeComponent(); DataContext = new LoginViewModel(); } }
Momentan habe ich nur eine Schaltfläche (Login-Button) in der LoginMainView. Wenn ich auf diese Schaltfläche klicke, sollte die aktuelle LoginMainView mit der MainMainView ausgetauscht werden.
<Grid> <Button Content="Main" Background="Red" Command="{Binding SwitchMainViewCommand}" /> </Grid>
MainMainView
public partial class MainMainView : UserControl { public LoginMainView() { InitializeComponent(); DataContext = new MainViewModel(); } }
hier die gleiche (Logout-Button) entsprechen LoginMainView ...
<Grid> <Button Content="Logout" Background="Green" Command="{Binding SwitchMainViewCommand}" /> </Grid>
Mainwindow
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainWindowViewModel(); } }
Im MainWindow- View Ich binde die CurrentMainView-Eigenschaft (MainViewType) vom BaseMainViewViewModel an den contentpresenter, den ich durch Klicken auf den Button in der MainMainView/LoginMainView und den ValueConverter ändern werde.
<Grid> <StackPanel> <Label Content="Test" /> <ContentPresenter Content="{Binding CurrentMainView, Converter={view:MainViewValueConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </StackPanel> </Grid>
MainViewType
public enum MainViewType { Login = 0, Main = 1 }
BaseValueConverter
public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter where T : class, new() { private static T _Converter = null; public override object ProvideValue(IServiceProvider serviceProvider) { return _Converter ?? (_Converter = new T()); } public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture); public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); }
RelayCommand
public class RelayCommand : ICommand { private Action<object> _Execute; private Predicate<object> _CanExecute; private event EventHandler CanExecuteChangedInternal; public RelayCommand(Action<object> execute) : this(execute, DefaultCanExecute) { } public RelayCommand(Action<object> execute, Predicate<object> canExecute) { _Execute = execute ?? throw new ArgumentNullException("execute"); _CanExecute = canExecute ?? throw new ArgumentNullException("canExecute"); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; CanExecuteChangedInternal += value; } remove { CommandManager.RequerySuggested -= value; CanExecuteChangedInternal -= value; } } public bool CanExecute(object parameter) { return (_CanExecute != null) && _CanExecute(parameter); } public void Execute(object parameter) { _Execute(parameter); } public void OnCanExecuteChanged() { EventHandler eventHandler = CanExecuteChangedInternal; if (eventHandler != null) { eventHandler.Invoke(this, EventArgs.Empty); } } public void Destroy() { _CanExecute = _ => false; _Execute = _ => { return; }; } private static bool DefaultCanExecute(object parameter) { return true; } }
Wenn ich die Anwendung starte, wird der ValueConverter aufgerufen und die richtige View (LoginMainView) wird geladen.Ich klicke dann auf den Button in der LoginMainView, der Befehl (SwitchMainView) wird ausgeführt, aber dann wird der Inhalt von MainWindow nicht in MainMainView geändert, da der ValueConverter nicht benutzt wird.
Was mache ich falsch? Habe ich ein grundsätzliches Verständnisproblem? Oder ist es auf diese Weise nicht möglich, das einfache Login/Logout-Szenario abzubilden? Oder habe ich einfach etwas übersehen? Kann mir bitte jemand sagen, was ich vergessen habe?
Vielen Dank im Voraus an die Helfer!
Ok, zunächst einmal vielen Dank für die Antwort. Aber um WPF und XAML besser zu lernen und zu verstehen, möchte ich das Rad neu erfinden. ;-) Was müsste ich tun, um es in der oben beschriebenen Weise zu implementieren? Was ich noch vermisse? Übrigens. Wo setze ich 'AppBootstraper.ActiveViewModel = neues LoginViewModel()'? Muss ich zwei Befehle dafür anlegen und an die entsprechenden Buttons binden? – srcalex
Ich habe meine Antwort bearbeitet –