从子MVVM更新父视图

时间:2013-11-21 05:26:46

标签: c# wpf mvvm

我正在构建一个WPF MVVM应用程序但是我在从子视图模型更新父视图时遇到了问题。

我在父视图模型上调用doAction()方法,该方法更新属性并引发PropertyChangeEvent。当从MainViewModel调用此方法时,一切都很好,但是当我从子视图模型调用相同的方法时,会引发PropertyChangedEvent get,但视图不会更新。

示例:

ChildViewModel()
{
    private ParentViewModel parent; 

    parent.doAction(); // Raised event but MainView doesn't update
}

ParentViewModel()
{
    public void doAction()
    {
        this.Property = true;
        OnPropertyChange("Property"); 
    }
}

我的视图是使用XAML创建的:

<MainView>
   <TabItem>
      <view:ChildView/>
   </TabItem>
</MainView>

Propery Change事件如此提出:

protected void OnPropertyChanged(string name)
{
    LOGGER.Info("Property Changed: " + name);
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}

我的问题是如何让父视图监听并更新由子视图引发的属性更改事件。

编辑:

基类:

public abstract class AbstractBaseViewModel : INotifyPropertyChanged
{

        public event PropertyChangedEventHandler PropertyChanged;
        public ICommand CloseCommand { get; set; }

        public AbstractBaseViewModel()
        {
            this.CloseCommand = new CloseCommand(this);
        }

        public void CloseWindow()
        {
            Application.Current.MainWindow.Close();
        }

        protected void OnPropertyChanged(string name)
        {
            LOGGER.Info("Property Changed: " + name);
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
}

父ViewModel:

public class ParentViewModel : AbstractBaseViewModel
{
        private Dispatcher dispatcher;
        private bool visible;

        public bool Visible
        {
            get { return visible; }
            set { visible= value; OnPropertyChanged("Visible"); }
        }

        public MainWindowViewModel()
        {
            this.dispatcher = Dispatcher.CurrentDispatcher;
            this.manager = manager;
        }

        public void ShowTab(){
            this.Visible = true;
        }
 }

儿童视图模型:

 public class ChildViewModel : AbstractBaseViewModel
 {

    private ParentViewModel parentVm;

    public GeneralViewModel(ParentViewModel vm)
    {
        this.parentVm= vm;
    }

    public void Command(){
        vm.ShowTab();
    }
 }

ParentView Xaml:

<TabItem Header="ViewWeWantToHide/Show" 
     Visibility="{Binding Visible,Converter={converter:BooleanToVisibilityConverter}}">
     <views:SomeOtherView/>
</TabItem>

<TabItem Header="ChildView Tab"> 
     <views:ChildView/>
</TabItem>

2 个答案:

答案 0 :(得分:1)

如果没有看到所有代码,很难猜出导致问题的原因。但是,我不得不说在WPF中更常见的是在UI中显示视图模型实例并让WPF自动显示相关视图,而不是直接显示视图。如果您使用视图模型而不是视图,那么您将可以从父视图模型访问子视图模型。

如果您这样做,或者确实可以从父视图模型访问子视图模型,那么我建议您使用简单的delegate将子视图模型中的“消息”传递给父视图而不是模型。您甚至可以定义无参数delegate并使用它来发送信号,而不是任何属性值。

您可以声明delegate,向您的孩子UserControl添加该类型的属性,并在主视图模型中附加处理程序。然后,您可以从您的孩子delegate调用UserControl,并在父视图模型的处理程序中调用您的方法。有关此技术的更多信息,请参阅我对Passing parameters between viewmodels问题的回答(它回答了类似但不完全相同的问题)。

答案 1 :(得分:0)

感谢大家的帮助。

我发现这个问题与WPF无关,实际上是我在子视图上设置datacontext的一个产物。在我的父窗口中,我使用Unity容器创建并注册了ParentViewModel的单例实例。然后将此实例注入到所有子视图中,问题是在创建父视图模型并使用unity容器注册之前调用了InitializeComponent方法,这意味着所有子视图都接收完全不同的实例。

不工作:

public MainWindow()
{

    InitializeComponent();

    if (DesignerProperties.GetIsInDesignMode(this))
    {
        this.DataContext = new ParentViewModel();
    }
    else
    {      
         IUnityContainer container = UnityFactory.Retrieve();

         ParentViewModel parentVM = container.Resolve<ParentViewModel>();
         container.RegisterInstance<ParentViewModel>(parentVM);

         this.DataContext = parentVM;

     }
}

工作:

public MainWindow()
{

    if (DesignerProperties.GetIsInDesignMode(this))
    {
        this.DataContext = new ParentViewModel();
    }
    else
    {     
         IUnityContainer container = UnityFactory.Retrieve();

         ParentViewModel parentVM = container.Resolve<ParentViewModel>();
         container.RegisterInstance<ParentViewModel>(parentVM );

         this.DataContext = parentVM;
     }

     /**
       * Initialize after registering parent VM and setting the datacontext
       */
     InitializeComponent();

  }