这是我在这里的第一个问题,请理解。我在这个问题上花了好几个小时挖掘,但对我来说什么都不管用,也许有人会给我解释这个奇怪的(对我来说(问题?我用MVVM 在WPF中制作了我的应用程序
我在MainWindow.xaml中使用了usercontrol,它加载带有绑定的视图:
<UserControl Content="{Binding CurrentView}" />
MainWindow DataContext是MainViewModel,它派生自BaseViewModel,我在其中设置和获取CurrentView,并实现INotifyPropertyChanged。
第一个CurrentView是LoginViewModel-它正确地加载在MainViewModel的构造函数中并设置视图(UsercontrolLoginview.xaml(。我不明白为什么当我从这个加载的LoginViewModel更改CurrentView属性时(它肯定会更改-我检查了它,并引发了NotifyPropertyChanged(-我的视图没有更改-它仍然是LoginView,但应该是WelcomeView。但是,当我用MainViewModel中的相同代码更改相同的属性时,我的视图会正确更改。有人可以指出哪里有错误?是否不可能从MainViewModel外部更改CurrentView属性,即使它不是MainViemodel的一部分,而是另一个类或其他什么?我在这里缺少什么?
代码:
public class BaseViewModel : NotifyPropertyChanged
{
private object? _currentView;
public object? CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged(nameof(CurrentView));
}
}
}
public class MainViewModel : BaseViewModel
{
public LoginViewModel LoginViewModel { get; set; }
public WelcomeViewModel WelcomeViewModel { get; set; }
[..]
public ICommand LoginCommand { get; set; } //- this works
public MainViewModel()
{
LoginViewModel = new();
WelcomeViewModel = new();
CurrentView = LoginViewModel;
// COMMANDS
LoginCommand = new RelayCommand(o => DoLogin(), o => CanLogin()); // this works
}
private bool CanLogin()
{
return true;
}
private void DoLogin()
{
CurrentView = WelcomeViewModel;
}
}
public class LoginViewModel : BaseViewModel
{
[...]
public WelcomeViewModel WelcomeViewModel { get; set; }
// COMMANDS PROPERTIES
public ICommand LoginCommand { get; set; }
public LoginViewModel()
{
WelcomeViewModel = new();
LoginCommand = new RelayCommand(o => DoLogin(), o => CanLogin());
}
private bool CanLogin()
{
return true;
}
private void DoLogin()
{
MessageBox.Show("Login!"); // message box test showes
// here will be some authentication
CurrentView = WelcomeViewModel; // property CurrentView changes
// CurrentView = new MainViewModel().WelcomeViewModel; // this way also doesn't work
}
}
最后是来自UserControl LoginView.XAML的XAML(命令运行正常,属性CurrentView更改,但视图保持不变:
<Button
Width="200"
Height="50"
Margin="10"
Command="{Binding LoginCommand}"
Content="Login"
FontSize="18" />
<!-- Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},
Path=DataContext.LoginCommand}" THIS WORKS! -->
App.xaml具有:
<DataTemplate DataType="{x:Type vievmodels:LoginViewModel}">
<viewscontents:LoginView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vievmodels:WelcomeViewModel}">
<viewscontents:WelcomeView/>
</DataTemplate>
问题是:如何设置DataContext。。。。这样做。
主视图模型:
public class MainViewModel : BaseInpc
{
#region CurrentContent
private object? _currentContent;
public object? CurrentContent { get => _currentContent; set => Set(ref _currentContent, value); }
private RelayCommand _setCurrentCommand;
public RelayCommand SetCurrentCommand => _setCurrentCommand
??= new RelayCommand(content => CurrentContent = content);
#endregion
public LoginViewModel LoginViewModel { get; } = new LoginViewModel();
public WelcomeViewModel WelcomeViewModel { get; } = new WelcomeViewModel();
public MainViewModel()
{
CurrentContent = WelcomeViewModel;
}
}
public class WelcomeViewModel: BaseInpc // Derived not from MainViewModel!
{
// Some Code
}
public class LoginViewModel: BaseInpc // Derived not from MainViewModel!
{
// Some Code
}
在应用程序资源中创建MainViewModel的实例:
<Application.Resources>
<local:MainViewModel x:Key="mainVM"/>
</Application.Resources>
在Windows XAML中:
<Window ------------
------------
DataContext="{DynamicResource mainVM}">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LoginViewModel}">
<local:LoginViewUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type WelcomeViewModel}">
<local:WelcomeViewUserControl/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentContent}"/>
按钮切换CurrentContent:的示例
<Button Command="{Binding SetCurrentCommand, Source={StaticResource mainVM}}"
CommandParameter="{Binding LoginViewModel, Source={StaticResource mainVM}}"/>
BaseInpc和RelayCommand类。
您犯的错误是有两个CurrentView
变量。一个在CCD_ 2中,另一个则在LoginViewModel
中。这两个类都是从BaseViewModel
派生的,但这并不意味着它们共享CurrentView
的同一实例。两者都有一个CurrentView
变量的新实例。意味着只有一个绑定到页面的DataContext
。
我看不到的是,你把哪个CurrentView
分配给DataContext
。所以我不能完全回答这个问题。
但是看起来你有一个窗口,里面有两个控件。要解决此问题,您应该创建一个仅包含CurrentView
的第三视图模型。在使用UserControl
的父级上使用此实例。并将其他ViewModels用于用户控件本身。