[英]WPF binding doesn't work when property changes
這是我在這里的第一個問題,請理解。 我已經在這個問題上花費了幾個小時來挖掘對我沒有用的東西,也許有人會向我解釋這個奇怪的(對我來說)問題? 我用 MVVM 在 WPF 中制作了我的應用程序
我使用用戶控件進入 MainWindow.xaml ,它通過綁定加載視圖:
<UserControl Content="{Binding CurrentView}" />
MainWindow DataContext 是 MainViewModel,它派生自 BaseViewModel,我從中設置和獲取 CurrentView 並實現 INotifyPropertyChanged。
第一個 CurrentView 是 LoginViewModel - 它正確加載到 MainViewModel 的構造函數中並設置視圖(Usercontrol Loginview.xaml)。 而且我不明白為什么當我從這個加載的 LoginViewModel 更改 CurrentView 屬性時(它肯定會改變 - 我檢查了它並且 NotifyPropertyChanged 引發了) - 我的視圖沒有改變 - 它仍然是 LoginView,但應該是 WelcomeView。 但是,當我使用 MainViewModel 中的相同代碼更改相同的屬性時 - 我的視圖會正確更改。 有人可以指出哪里有錯誤? 是否不可能從 MainViewModel 外部更改 CurrentView 屬性,即使它不是 MainViemodel 的一部分,而是另一個 class 或什么? 我在這里缺少什么?
代碼:
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>
您犯的錯誤是有兩個CurrentView
變量。 一個在MainViewModel
中,另一個在LoginViewModel
中。 這兩個類都是從BaseViewModel
派生的,但這並不意味着它們共享相同的CurrentView
實例。 兩者都有CurrentView
變量的新實例。 這意味着只有一個綁定到頁面的DataContext
。
在您將哪個CurrentView
分配給DataContext
時,我看不到它。 所以我無法完全回答這個問題。
但看起來你有 1 個 window 填充了 2 個控件。 要解決這個問題,您應該創建一個僅包含CurrentView
的第三個 ViewModel。 在使用UserControl
的父級上使用此實例。 並將其他 ViewModel 用於用戶控件本身。
問題是:如何設置 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}}"/>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.