如何在多个视图之间共享绑定值?
How to share a binding value between multiple views?
我是 WPF 和 MVVM(来自 WinForms 和 Events)的新手,所以请多多包涵!
我想弄清楚如何在多个视图之间使用相同的 INotifyPropertyChanged
值绑定。我正在使用 MVVM Light。我有继承自 ViewModelBase
的 ViewModels 支持我的视图(没有代码隐藏)。我不确定如何解释这个问题,但我认为一个例子可以清楚地说明我在追求什么。
我有一个主window。它有一个标准 TabControl
。在登录 TabItem
我有一个自定义登录控件。在 TabControl
下面,我有一个自定义状态栏控件。期望的行为是当用户登录时,状态栏会更新他们的登录状态和名称,并且主 window 上的其他 TabItem
s 变为启用(它们应该在未登录时被禁用中).
总而言之,我有:
- MainWindow(视图)与 MainWindowViewModel
- 使用 LoginViewModel 登录(视图)(在 MainWindow 的
TabControl
中)
- 带有 StatusBarViewModel(位于主窗口底部)的 StatusBar(视图)
这是我的 StatusBarViewModel
的样子:
public class StatusBarViewModel : ViewModelBase, IStatusBarViewModel
{
private bool _isLoggedIn;
public bool IsLoggedIn
{
get { return _isLoggedIn; }
set { Set(ref _isLoggedIn, value); RaisePropertyChanged(); }
}
// other properties follow
}
我通过构造函数注入将 IStatusBarViewModel
的(单例)具体实例注入(使用 Ninject)到 LoginViewModel 中:
public class LoginViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public LoginViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
我对 MainWindowViewModel 执行相同的操作:
public class MainWindowViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public bool IsLoggedIn => _statusBar.IsLoggedIn;
public MainWindowViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
注意:我认为这就是我的问题所在...不确定 MVVM Light 是否将其解释为可绑定 属性 并应用适当的更改通知。如果我添加一个 setter(我在这里不需要),那将不起作用,因为 A property or indexer may not be passed as an out or ref parameter
。所以我不清楚当我这样做时发生了什么。
回到正轨,所以当登录成功时,我可以像这样从 LoginViewModel
更新 IsLoggedIn
属性:
_statusBar.IsLoggedIn = true;
我在主窗口 XAML 中设置了绑定,如下所示:
<TabItem Header="Event" IsEnabled="{Binding IsLoggedIn}">
<views:Events/>
</TabItem>
首次加载视图时绑定工作正常,但对 属性 的后续更改不会触发 IsEnabled
中的更改。然而,StatusBar(视图)确实会相应更新。
我考虑过将对 StatusBarViewModel 和 MainWindowViewModel 的引用都注入到我的 LoginViewModel 中的想法(然后必须在登录后设置两个属性),但这让我觉得我没有正确地处理这个问题因为我正在创建依赖项。
所以基本上问题是:
- 根据 MVVM 模式,我的方法是否正确?
- 我的方向是否正确,只需要稍微修改一下代码?
- 如果不是,处理这种情况的(或)标准模式是什么?
你猜对了。问题在这里:
public bool IsLoggedIn => _statusBar.IsLoggedIn;
... 因为它不会生成更改通知。您可以做的只是通过 public 属性 公开 IStatusBarViewModel,然后直接绑定到它自己的 IsLoggedIn 属性。
在视图模型中:
public class MainWindowViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public IStatusBarViewModel StatusBar => _statusBar;
public MainWindowViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
在视图中:
<TabItem Header="Event" IsEnabled="{Binding StatusBar.IsLoggedIn}">
<views:Events/>
</TabItem>
我是 WPF 和 MVVM(来自 WinForms 和 Events)的新手,所以请多多包涵!
我想弄清楚如何在多个视图之间使用相同的 INotifyPropertyChanged
值绑定。我正在使用 MVVM Light。我有继承自 ViewModelBase
的 ViewModels 支持我的视图(没有代码隐藏)。我不确定如何解释这个问题,但我认为一个例子可以清楚地说明我在追求什么。
我有一个主window。它有一个标准 TabControl
。在登录 TabItem
我有一个自定义登录控件。在 TabControl
下面,我有一个自定义状态栏控件。期望的行为是当用户登录时,状态栏会更新他们的登录状态和名称,并且主 window 上的其他 TabItem
s 变为启用(它们应该在未登录时被禁用中).
总而言之,我有:
- MainWindow(视图)与 MainWindowViewModel
- 使用 LoginViewModel 登录(视图)(在 MainWindow 的
TabControl
中) - 带有 StatusBarViewModel(位于主窗口底部)的 StatusBar(视图)
这是我的 StatusBarViewModel
的样子:
public class StatusBarViewModel : ViewModelBase, IStatusBarViewModel
{
private bool _isLoggedIn;
public bool IsLoggedIn
{
get { return _isLoggedIn; }
set { Set(ref _isLoggedIn, value); RaisePropertyChanged(); }
}
// other properties follow
}
我通过构造函数注入将 IStatusBarViewModel
的(单例)具体实例注入(使用 Ninject)到 LoginViewModel 中:
public class LoginViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public LoginViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
我对 MainWindowViewModel 执行相同的操作:
public class MainWindowViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public bool IsLoggedIn => _statusBar.IsLoggedIn;
public MainWindowViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
注意:我认为这就是我的问题所在...不确定 MVVM Light 是否将其解释为可绑定 属性 并应用适当的更改通知。如果我添加一个 setter(我在这里不需要),那将不起作用,因为 A property or indexer may not be passed as an out or ref parameter
。所以我不清楚当我这样做时发生了什么。
回到正轨,所以当登录成功时,我可以像这样从 LoginViewModel
更新 IsLoggedIn
属性:
_statusBar.IsLoggedIn = true;
我在主窗口 XAML 中设置了绑定,如下所示:
<TabItem Header="Event" IsEnabled="{Binding IsLoggedIn}">
<views:Events/>
</TabItem>
首次加载视图时绑定工作正常,但对 属性 的后续更改不会触发 IsEnabled
中的更改。然而,StatusBar(视图)确实会相应更新。
我考虑过将对 StatusBarViewModel 和 MainWindowViewModel 的引用都注入到我的 LoginViewModel 中的想法(然后必须在登录后设置两个属性),但这让我觉得我没有正确地处理这个问题因为我正在创建依赖项。
所以基本上问题是:
- 根据 MVVM 模式,我的方法是否正确?
- 我的方向是否正确,只需要稍微修改一下代码?
- 如果不是,处理这种情况的(或)标准模式是什么?
你猜对了。问题在这里:
public bool IsLoggedIn => _statusBar.IsLoggedIn;
... 因为它不会生成更改通知。您可以做的只是通过 public 属性 公开 IStatusBarViewModel,然后直接绑定到它自己的 IsLoggedIn 属性。
在视图模型中:
public class MainWindowViewModel : ViewModelBase
{
private IStatusBarViewModel _statusBar;
public IStatusBarViewModel StatusBar => _statusBar;
public MainWindowViewModel(IStatusBarViewModel statusBar)
{
_statusBar = statusBar;
}
}
在视图中:
<TabItem Header="Event" IsEnabled="{Binding StatusBar.IsLoggedIn}">
<views:Events/>
</TabItem>