WPF绑定到全局变量以更新UI

时间:2017-09-30 14:53:06

标签: c# .net wpf mvvm

我们说我有两个窗口和一个trayicon上下文菜单。每个窗口都有一个togglebutton,上下文菜单有一个可检查的菜单项。所有三个控件都旨在显示和切换相同值的状态。

如何将三个控件中的三个控件绑定到单个全局变量(在这种情况下为IsChecked),当检查/取消选中其中一个控件时,其他控件将相应更新?我应该只是进行调用还是有MVVM解决方案?我是WPF的新手,所以我不确定最好/最正确的方法。

2 个答案:

答案 0 :(得分:1)

假设您有WindowA,WindowB,...,WindowN并假设它们都是不同类型的。

创建一个类,比如CommonState,它封装了所有常见属性,命令等,实现了INotifyPropertyChanged

public class CommonState : INotifyPropertyChanged
{
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private bool _isChecked;

    public bool IsChecked
    {
        get { return _isChecked; }
        set
        {
            if (value != _isChecked)
            {
                _isChecked = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

然后声明一个接口:

public interface ICommonStateWindow
{
    CommonState { get; set; }
}

让每个窗口实现此接口:

public partial class WindowA : Window, ICommonState
{
    public WindowA()
    {
        InitializeComponent();
    }

    // This property will be injected, do not re-assign
    public CommonState CommonState { get; set; }
}

在显示之前在每个窗口中注入公共状态,例如:

public partial class App : Application
{
    private CommonState _state;

    protected override void OnStartup(StartupEventArgs e)
    {
        _state = new CommonState() {IsChecked = true};

        var wndA = new WindowA() { CommonState = _state };
        var wndB = new WindowB() { CommonState = _state };

        wndA.Show();
        wndB.Show();
    }
}

请记住在一些长生命对象(如App或主窗口)中至少保留一个对创建的CommonState的引用,因此它不会在某个时刻收集垃圾。

在XAML中,您应该使用RelativeSource进行绑定,这样您创建的每种新类型的窗口都可以拥有自己独立的ViewModel(DataContext):

<Window x:Class="Example.WindowA"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WindowA" Height="300" Width="300">
    <Grid>
        <CheckBox IsChecked="{Binding CommonState.IsChecked, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
    </Grid>
</Window>

这个例子,我演示的不是唯一的方式,我不会说&#34;最好的&#34;,但它解决了以下问题:

  1. 封装公共(共享)状态
  2. 同步窗口的不同实例(或类型)之间的状态
  3. 允许独立于窗口实现扩展CommonState(仅需要更新XAML)
  4. 另一种可能的解决方案是将CommonState的单例实例注册到静态公开的控制容器(IoC)反转中,并使每个具体窗口的ViewModel获得一个实例。这样您就可以避免注射步骤。对于小型项目来说,这将是一种过度杀伤

    我有人试图运行上面的代码,记得删除StartupUri =&#34; MainWindow.xaml&#34;来自App.xaml

答案 1 :(得分:0)

您可以添加到您的代码隐藏bool IsChecked属性,并将其用于您想要的所有组件。你可以改变它的组件&#39; event方法为true或false。