Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 是否更新对嵌套ViewModel命令的引用?_Wpf_Mvvm_Command_Viewmodel - Fatal编程技术网

Wpf 是否更新对嵌套ViewModel命令的引用?

Wpf 是否更新对嵌套ViewModel命令的引用?,wpf,mvvm,command,viewmodel,Wpf,Mvvm,Command,Viewmodel,我知道我可能错过了一些简单而明显的东西,但目前我还没有意识到 我正在尝试使用MVVM模式 如何更新对链接到子viewmodel的viewmodel中的命令的引用 我已将视图(MainView)绑定到viewmodel(MainViewModel)。 在MainView上,我有一个绑定到viewmodel(SummaryViewModel)的另一个视图(SummaryView)的实例。SummaryViewModel包含第三个viewmodel(SummaryFilterViewModel)的集合

我知道我可能错过了一些简单而明显的东西,但目前我还没有意识到

我正在尝试使用MVVM模式

如何更新对链接到子viewmodel的viewmodel中的命令的引用

我已将视图(MainView)绑定到viewmodel(MainViewModel)。 在MainView上,我有一个绑定到viewmodel(SummaryViewModel)的另一个视图(SummaryView)的实例。SummaryViewModel包含第三个viewmodel(SummaryFilterViewModel)的集合

在SummaryView上,有一个TabControl,其中的每个选项卡都绑定到SummaryViewModel集合中的一个SummaryFilterServiceWModel实例

在MainView上,有一个按钮绑定到MainViewModel中的命令

我想让命令逻辑存在于SummaryFilterServiceWModel类中。因此,无论当前显示哪个选项卡,都需要连接到MainView上的按钮触发的命令

我想做的是:

  • 存储在SummaryViewModel集合中的各个SummaryFilterViewModel对象包含ShoutCommand的实际实现
  • MainView的XAML中的CommandReference对象绑定到MainViewModel的ShoutCommand属性
  • MainViewModel的ShoutCommand属性返回对存储在MainViewModel中的SummaryViewModel对象的ShoutCommand属性的引用
  • SummaryViewModel的ShoutCommand属性返回对当前所选SummaryFilterServiceWModel的ShoutCommand属性的引用
  • 发生的情况是,当用户更改选项卡时,命令不会得到更新

    我在如何实现这一点上偏离了基准吗? 我是否需要将命令的实现移动到SummaryViewModel类中

    提前感谢您的帮助

    我的解决方案的来源如下所示:

    视图模型 SummaryView.xaml

    public MainViewModel()
    {
        _SummaryViewModel = new SummaryViewModel();
        _SummaryViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_SummaryViewModel_PropertyChanged);
    }
    
    void _SummaryViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "ShoutCommand":
                OnPropertyChanged(this, "ShoutCommand");
                break;
        }
    }
    
    private SummaryViewModel _SummaryViewModel;
    public SummaryViewModel SummaryViewModel {...}
    
    public ICommand ShoutCommand
    {
        get { return _SummaryViewModel.ShoutCommand; }
    }
    
    private List<SummaryFilterViewModel> _Filters;
    public List<SummaryFilterViewModel> Filters {...}
    
    private int _SelectedTabIndex;
    public int SelectedTabIndex 
    {
        get { return _SelectedTabIndex; }
        set
        {
            _SelectedTabIndex = value;
            OnPropertyChanged(this, "SelectedTabIndex");
            OnPropertyChanged(this, "ShoutCommand");
        }
    }
    
    public ICommand ShoutCommand
    {
        get {
            int selectedTabIndex = SelectedTabIndex;
    
            return (selectedTabIndex == -1) ? null : Filters[SelectedTabIndex].ShoutCommand; 
        }
    }
    
    MainViewModel.cs

    SummaryViewModel.cs

    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    使用NestedCommands.Commands;
    使用System.Windows.Input;
    命名空间NestedCommands.ViewModels
    {
    类SummaryViewModel:ViewModelBase
    {
    #区域构造函数
    公共摘要视图模型()
    {
    列表过滤器=新列表();
    添加(新的SummaryFilterViewModel(“过滤器1”);
    添加(新的SummaryFilterViewModel(“过滤器2”);
    添加(新的SummaryFilterViewModel(“过滤器3”);
    过滤器=过滤器;
    }
    #端区
    #区域属性
    私有列表过滤器;
    公共列表过滤器
    {
    获取{return\u Filters;}
    设置
    {
    _过滤器=值;
    OnPropertyChanged(本“过滤器”);
    }
    }
    私有int_选择的TABINDEX;
    公共int-SelectedTabIndex
    {
    获取{return\u SelectedTabIndex;}
    设置
    {
    _SelectedTabIndex=值;
    已更改的不动产(此为“选定的数据索引”);
    }
    }
    #端区
    #区域命令引用
    公共ICommand ShoutCommand
    {
    获取{返回筛选器[SelectedTabIndex].ShoutCommand;}
    }
    #端区
    }
    }
    
    SummaryFilterViewModel.cs

    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    使用NestedCommands.Commands;
    使用System.Windows.Input;
    命名空间NestedCommands.ViewModels
    {
    类SummaryFilterViewModel:ViewModelBase
    {
    #区域构造函数
    公共摘要筛选器服务模型(字符串筛选器名称)
    {
    this.FilterName=FilterName;
    List listData=新列表();
    对于(int i=1;i<10;i++)
    {
    Add(string.Format(“{0}:{1}”,FilterName,i));
    }
    ListData=ListData;
    }
    #端区
    #区域属性
    私有字符串过滤器名称;
    公共字符串筛选器名称
    {
    获取{return\u FilterName;}
    设置
    {
    _过滤器名称=值;
    已更改的不动产(本“过滤器名称”);
    }
    }
    私有列表ListData;
    公共列表数据
    {
    获取{return\u ListData;}
    设置
    {
    _ListData=值;
    OnPropertyChanged(本“列表数据”);
    }
    }
    #端区
    #区域呼叫命令
    专用授权命令(u ShoutCommand);;
    公共ICommand ShoutCommand
    {
    获取{return _ShoutCommand???(_ShoutCommand=newdelegatecommand(Shout,CanShout));}
    }
    私家侦探()
    {
    System.Windows.MessageBox.Show(string.Format(“从SummaryFilterWebModel:{0}”,FilterName调用”);
    }
    二等兵布尔·坎豪特()
    {
    返回true;
    }
    #端区
    }
    }
    
    你的帖子很长,我承认我没有完全阅读。但是,我不明白
    CommandReference
    的目的。为什么不直接绑定到
    MainViewModel.ShoutCommand
    ?考虑:

    • TabControl
      ItemsSource
      绑定到子视图模型集合
    • TabControl
      SelectedItem
      绑定到跟踪所选子视图模型的另一个属性
    • 当上述属性更改时,也为
      ShoutCommand
      属性引发
      PropertyChanged
      事件
    • ShoutCommand
      属性的getter中,只需返回所选子视图模型的
      ShoutCommand
      • 您的采购订单
        using System;
        using System.Windows;
        using System.Windows.Input;
        
        namespace NestedCommands.Commands
        {
            /// <summary>
            /// This class facilitates associating a key binding in XAML markup to a command
            /// defined in a View Model by exposing a Command dependency property.
            /// The class derives from Freezable to work around a limitation in WPF when data-binding from XAML.
            /// </summary>
            public class CommandReference : Freezable, ICommand
            {
                public CommandReference()
                {
                    // Blank
                }
        
                public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference), new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
        
                public ICommand Command
                {
                    get { return (ICommand)GetValue(CommandProperty); }
                    set { SetValue(CommandProperty, value); }
                }
        
                #region ICommand Members
        
                public bool CanExecute(object parameter)
                {
                    if (Command != null)
                        return Command.CanExecute(parameter);
                    return false;
                }
        
                public void Execute(object parameter)
                {
                    Command.Execute(parameter);
                }
        
                public event EventHandler CanExecuteChanged;
        
                private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    CommandReference commandReference = d as CommandReference;
                    ICommand oldCommand = e.OldValue as ICommand;
                    ICommand newCommand = e.NewValue as ICommand;
        
                    if (oldCommand != null)
                    {
                        oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;
                    }
                    if (newCommand != null)
                    {
                        newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;
                    }
                }
        
                #endregion
        
                #region Freezable
        
                protected override Freezable CreateInstanceCore()
                {
                    throw new NotImplementedException();
                }
        
                #endregion
            }
        }
        
        using System;
        using System.Collections.Generic;
        using System.Windows;
        using System.Windows.Input;
        
        namespace NestedCommands.Commands
        {
            /// <summary>
            ///     This class allows delegating the commanding logic to methods passed as parameters,
            ///     and enables a View to bind commands to objects that are not part of the element tree.
            /// </summary>
            public class DelegateCommand : ICommand
            {
                #region Constructors
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action executeMethod)
                    : this(executeMethod, null, false)
                {
                }
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
                    : this(executeMethod, canExecuteMethod, false)
                {
                }
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
                {
                    if (executeMethod == null)
                    {
                        throw new ArgumentNullException("executeMethod");
                    }
        
                    _executeMethod = executeMethod;
                    _canExecuteMethod = canExecuteMethod;
                    _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
                }
        
                #endregion
        
                #region Public Methods
        
                /// <summary>
                ///     Method to determine if the command can be executed
                /// </summary>
                public bool CanExecute()
                {
                    if (_canExecuteMethod != null)
                    {
                        return _canExecuteMethod();
                    }
                    return true;
                }
        
                /// <summary>
                ///     Execution of the command
                /// </summary>
                public void Execute()
                {
                    if (_executeMethod != null)
                    {
                        _executeMethod();
                    }
                }
        
                /// <summary>
                ///     Property to enable or disable CommandManager's automatic requery on this command
                /// </summary>
                public bool IsAutomaticRequeryDisabled
                {
                    get
                    {
                        return _isAutomaticRequeryDisabled;
                    }
                    set
                    {
                        if (_isAutomaticRequeryDisabled != value)
                        {
                            if (value)
                            {
                                CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
                            }
                            else
                            {
                                CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
                            }
                            _isAutomaticRequeryDisabled = value;
                        }
                    }
                }
        
                /// <summary>
                ///     Raises the CanExecuteChaged event
                /// </summary>
                public void RaiseCanExecuteChanged()
                {
                    OnCanExecuteChanged();
                }
        
                /// <summary>
                ///     Protected virtual method to raise CanExecuteChanged event
                /// </summary>
                protected virtual void OnCanExecuteChanged()
                {
                    CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
                }
        
                #endregion
        
                #region ICommand Members
        
                /// <summary>
                ///     ICommand.CanExecuteChanged implementation
                /// </summary>
                public event EventHandler CanExecuteChanged
                {
                    add
                    {
                        if (!_isAutomaticRequeryDisabled)
                        {
                            CommandManager.RequerySuggested += value;
                        }
                        CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
                    }
                    remove
                    {
                        if (!_isAutomaticRequeryDisabled)
                        {
                            CommandManager.RequerySuggested -= value;
                        }
                        CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
                    }
                }
        
                bool ICommand.CanExecute(object parameter)
                {
                    return CanExecute();
                }
        
                void ICommand.Execute(object parameter)
                {
                    Execute();
                }
        
                #endregion
        
                #region Data
        
                private readonly Action _executeMethod = null;
                private readonly Func<bool> _canExecuteMethod = null;
                private bool _isAutomaticRequeryDisabled = false;
                private List<WeakReference> _canExecuteChangedHandlers;
        
                #endregion
            }
        
            /// <summary>
            ///     This class allows delegating the commanding logic to methods passed as parameters,
            ///     and enables a View to bind commands to objects that are not part of the element tree.
            /// </summary>
            /// <typeparam name="T">Type of the parameter passed to the delegates</typeparam>
            public class DelegateCommand<T> : ICommand
            {
                #region Constructors
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action<T> executeMethod)
                    : this(executeMethod, null, false)
                {
                }
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
                    : this(executeMethod, canExecuteMethod, false)
                {
                }
        
                /// <summary>
                ///     Constructor
                /// </summary>
                public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
                {
                    if (executeMethod == null)
                    {
                        throw new ArgumentNullException("executeMethod");
                    }
        
                    _executeMethod = executeMethod;
                    _canExecuteMethod = canExecuteMethod;
                    _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
                }
        
                #endregion
        
                #region Public Methods
        
                /// <summary>
                ///     Method to determine if the command can be executed
                /// </summary>
                public bool CanExecute(T parameter)
                {
                    if (_canExecuteMethod != null)
                    {
                        return _canExecuteMethod(parameter);
                    }
                    return true;
                }
        
                /// <summary>
                ///     Execution of the command
                /// </summary>
                public void Execute(T parameter)
                {
                    if (_executeMethod != null)
                    {
                        _executeMethod(parameter);
                    }
                }
        
                /// <summary>
                ///     Raises the CanExecuteChaged event
                /// </summary>
                public void RaiseCanExecuteChanged()
                {
                    OnCanExecuteChanged();
                }
        
                /// <summary>
                ///     Protected virtual method to raise CanExecuteChanged event
                /// </summary>
                protected virtual void OnCanExecuteChanged()
                {
                    CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
                }
        
                /// <summary>
                ///     Property to enable or disable CommandManager's automatic requery on this command
                /// </summary>
                public bool IsAutomaticRequeryDisabled
                {
                    get
                    {
                        return _isAutomaticRequeryDisabled;
                    }
                    set
                    {
                        if (_isAutomaticRequeryDisabled != value)
                        {
                            if (value)
                            {
                                CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
                            }
                            else
                            {
                                CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
                            }
                            _isAutomaticRequeryDisabled = value;
                        }
                    }
                }
        
                #endregion
        
                #region ICommand Members
        
                /// <summary>
                ///     ICommand.CanExecuteChanged implementation
                /// </summary>
                public event EventHandler CanExecuteChanged
                {
                    add
                    {
                        if (!_isAutomaticRequeryDisabled)
                        {
                            CommandManager.RequerySuggested += value;
                        }
                        CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
                    }
                    remove
                    {
                        if (!_isAutomaticRequeryDisabled)
                        {
                            CommandManager.RequerySuggested -= value;
                        }
                        CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
                    }
                }
        
                bool ICommand.CanExecute(object parameter)
                {
                    // if T is of value type and the parameter is not
                    // set yet, then return false if CanExecute delegate
                    // exists, else return true
                    if (parameter == null &&
                        typeof(T).IsValueType)
                    {
                        return (_canExecuteMethod == null);
                    }
                    return CanExecute((T)parameter);
                }
        
                void ICommand.Execute(object parameter)
                {
                    Execute((T)parameter);
                }
        
                #endregion
        
                #region Data
        
                private readonly Action<T> _executeMethod = null;
                private readonly Func<T, bool> _canExecuteMethod = null;
                private bool _isAutomaticRequeryDisabled = false;
                private List<WeakReference> _canExecuteChangedHandlers;
        
                #endregion
            }
        
            /// <summary>
            ///     This class contains methods for the CommandManager that help avoid memory leaks by
            ///     using weak references.
            /// </summary>
            internal class CommandManagerHelper
            {
                internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
                {
                    if (handlers != null)
                    {
                        // Take a snapshot of the handlers before we call out to them since the handlers
                        // could cause the array to me modified while we are reading it.
        
                        EventHandler[] callees = new EventHandler[handlers.Count];
                        int count = 0;
        
                        for (int i = handlers.Count - 1; i >= 0; i--)
                        {
                            WeakReference reference = handlers[i];
                            EventHandler handler = reference.Target as EventHandler;
                            if (handler == null)
                            {
                                // Clean up old handlers that have been collected
                                handlers.RemoveAt(i);
                            }
                            else
                            {
                                callees[count] = handler;
                                count++;
                            }
                        }
        
                        // Call the handlers that we snapshotted
                        for (int i = 0; i < count; i++)
                        {
                            EventHandler handler = callees[i];
                            handler(null, EventArgs.Empty);
                        }
                    }
                }
        
                internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
                {
                    if (handlers != null)
                    {
                        foreach (WeakReference handlerRef in handlers)
                        {
                            EventHandler handler = handlerRef.Target as EventHandler;
                            if (handler != null)
                            {
                                CommandManager.RequerySuggested += handler;
                            }
                        }
                    }
                }
        
                internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
                {
                    if (handlers != null)
                    {
                        foreach (WeakReference handlerRef in handlers)
                        {
                            EventHandler handler = handlerRef.Target as EventHandler;
                            if (handler != null)
                            {
                                CommandManager.RequerySuggested -= handler;
                            }
                        }
                    }
                }
        
                internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
                {
                    AddWeakReferenceHandler(ref handlers, handler, -1);
                }
        
                internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
                {
                    if (handlers == null)
                    {
                        handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
                    }
        
                    handlers.Add(new WeakReference(handler));
                }
        
                internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
                {
                    if (handlers != null)
                    {
                        for (int i = handlers.Count - 1; i >= 0; i--)
                        {
                            WeakReference reference = handlers[i];
                            EventHandler existingHandler = reference.Target as EventHandler;
                            if ((existingHandler == null) || (existingHandler == handler))
                            {
                                // Clean up old handlers that have been collected
                                // in addition to the handler that is to be removed.
                                handlers.RemoveAt(i);
                            }
                        }
                    }
                }
            }
        }
        
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.ComponentModel;
        
        namespace NestedCommands.ViewModels
        {
            class ViewModelBase : INotifyPropertyChanged
            {
                public event PropertyChangedEventHandler PropertyChanged;
        
                protected void OnPropertyChanged(object sender, string propertyName)
                {
                    if (this.PropertyChanged != null)
                    {
                        PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
                    }
                }
            }
        }
        
        using System;
        using System.Windows.Input;
        
        namespace NestedCommands.ViewModels
        {
            class MainViewModel : ViewModelBase
            {
                public MainViewModel()
                {
                    _SummaryViewModel = new SummaryViewModel();
                }
        
                private SummaryViewModel _SummaryViewModel;
                public SummaryViewModel SummaryViewModel
                {
                    get { return _SummaryViewModel; }
                    set
                    {
                        _SummaryViewModel = value;
                        OnPropertyChanged(this, "SummaryViewModel");
                    }
                }
        
                public ICommand ShoutCommand
                {
                    get { return _SummaryViewModel.ShoutCommand; }
                }
            }
        }
        
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using NestedCommands.Commands;
        using System.Windows.Input;
        
        namespace NestedCommands.ViewModels
        {
            class SummaryViewModel : ViewModelBase
            {
                #region Constructor
        
                public SummaryViewModel()
                {
                    List<SummaryFilterViewModel> filters = new List<SummaryFilterViewModel>();
                    filters.Add(new SummaryFilterViewModel("Filter 1"));
                    filters.Add(new SummaryFilterViewModel("Filter 2"));
                    filters.Add(new SummaryFilterViewModel("Filter 3"));
                    Filters = filters;
                }
        
                #endregion
        
                #region Properties
        
                private List<SummaryFilterViewModel> _Filters;
                public List<SummaryFilterViewModel> Filters
                {
                    get { return _Filters; }
                    set
                    {
                        _Filters = value;
                        OnPropertyChanged(this, "Filters");
                    }
                }
        
                private int _SelectedTabIndex;
                public int SelectedTabIndex
                {
                    get { return _SelectedTabIndex; }
                    set
                    {
                        _SelectedTabIndex = value;
                        OnPropertyChanged(this, "SelectedTabIndex");
                    }
                }
        
                #endregion
        
                #region Command References
        
                public ICommand ShoutCommand
                {
                    get { return Filters[SelectedTabIndex].ShoutCommand; }
                }
        
                #endregion
            }
        }
        
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using NestedCommands.Commands;
        using System.Windows.Input;
        
        namespace NestedCommands.ViewModels
        {
            class SummaryFilterViewModel : ViewModelBase
            {
                #region Constructor
        
                public SummaryFilterViewModel(string FilterName)
                {
                    this.FilterName = FilterName;
        
                    List<string> listData = new List<string>();
                    for (int i = 1; i < 10; i++)
                    {
                        listData.Add(string.Format("{0}: {1}", FilterName, i));
                    }
                    ListData = listData;
                }
        
                #endregion
        
                #region Properties
        
                private string _FilterName;
                public string FilterName
                {
                    get { return _FilterName; }
                    set
                    {
                        _FilterName = value;
                        OnPropertyChanged(this, "FilterName");
                    }
                }
        
                private List<string> _ListData;
                public List<string> ListData
                {
                    get { return _ListData; }
                    set
                    {
                        _ListData = value;
                        OnPropertyChanged(this, "ListData");
                    }
                }
        
                #endregion
        
                #region Shout Command
        
                private DelegateCommand _ShoutCommand;
                public ICommand ShoutCommand
                {
                    get { return _ShoutCommand ?? (_ShoutCommand = new DelegateCommand(Shout, CanShout)); }
                }
        
                private void Shout()
                {
                    System.Windows.MessageBox.Show(string.Format("Called from SummaryFilterViewModel: {0}", FilterName));
                }
        
                private bool CanShout()
                {
                    return true;
                }
        
                #endregion
            }
        }
        
        <v:SummaryView Grid.Row="0"
                       DataContext="{Binding SummaryViewModel}" />
        <Button Content="Shout Command"
                Grid.Row="1"
                Command="{Binding ShoutCommand}" />
        
        public MainViewModel()
        {
            _SummaryViewModel = new SummaryViewModel();
            _SummaryViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_SummaryViewModel_PropertyChanged);
        }
        
        void _SummaryViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "ShoutCommand":
                    OnPropertyChanged(this, "ShoutCommand");
                    break;
            }
        }
        
        private SummaryViewModel _SummaryViewModel;
        public SummaryViewModel SummaryViewModel {...}
        
        public ICommand ShoutCommand
        {
            get { return _SummaryViewModel.ShoutCommand; }
        }
        
        <TabControl SelectedIndex="{Binding SelectedTabIndex}">
            <TabItem DataContext="{Binding Filters[0]}" Header="{Binding FilterName}">
                <ListBox ItemsSource="{Binding ListData}" />
            </TabItem>
            <!-- TabItem repeated two more times -->
        </TabControl>
        
        private List<SummaryFilterViewModel> _Filters;
        public List<SummaryFilterViewModel> Filters {...}
        
        private int _SelectedTabIndex;
        public int SelectedTabIndex 
        {
            get { return _SelectedTabIndex; }
            set
            {
                _SelectedTabIndex = value;
                OnPropertyChanged(this, "SelectedTabIndex");
                OnPropertyChanged(this, "ShoutCommand");
            }
        }
        
        public ICommand ShoutCommand
        {
            get {
                int selectedTabIndex = SelectedTabIndex;
        
                return (selectedTabIndex == -1) ? null : Filters[SelectedTabIndex].ShoutCommand; 
            }
        }