当从另一个viewmodel调用函数时,RaisePropertyChanged不会触发

时间:2013-10-14 17:54:36

标签: c# wpf xaml windows-phone-7 mvvm

我在更新我正在处理的Windows Phone 7应用程序界面时出现问题。

我有MainPage.xaml及其MainViewModel.cs,用于处理子视图usercontrol ChildView1.xaml在主页中的显示方式。 ChildView1的ViewModel也是Child1ViewModel.cs。基本上,从MainPage触发myToggleButton会触发DataStateBehavior进入显示或隐藏状态以分别显示或隐藏ChildView1.xaml。 DataStateBehavior绑定到布尔值CanShowView,而myToggleButton绑定到Icommand名为ButtonChecked的{​​{1}},其中继函数SwitchVisibility将反转CanShowView 1}}布尔值来显示或隐藏视图。由于我使用的MVVM灯的RaisePropertyChanged,一切正常。

但是,ChildView1.xaml有一个myCloseButton,它应该从MainViewModel调用SwitchVisibility函数,后者又会还原CanShowViewRaisePropertyChangedCanShowView中应该触发ChildView1关闭,但问题是视图保持可见并且由于某种原因永远不会关闭!我通过调试器注意到RaisePropertyChanged中的CanShowView似乎没有触发。我想这就是问题所在。我做错了什么?我该怎么强迫它开火呢?我使用了多个RaisePropertyChanged但是似乎没有人发射,即使degugger显示我的函数中的值确实发生了变化。

这是我的代码。 MainPage.xaml中:

<phone:PhoneApplicationPage
    ...
>
    <phone:PhoneApplicationPage.DataContext>
        <Binding Path="Main" Source="{StaticResource Locator}"/>
    </phone:PhoneApplicationPage.DataContext>
    ...
    <Grid x:Name="LayoutRoot">
        ...
        <ToggleButton x:Name="myToggleButton" Command="{Binding Main.ButtonChecked, Source={StaticResource Locator}}" >
        <local:ChildView1 x:Name="myChildView1" Grid.Row="0" RenderTransformOrigin="0.5,0.5">
            <i:Interaction.Behaviors>
            <ec:DataStateBehavior Binding="{Binding Main.CanShowView, Source={StaticResource Locator}}" Value="True" TrueState="showChildView1" FalseState="hideChildView1"/>
        </i:Interaction.Behaviors>
        <local:ChildView1.RenderTransform>
            <CompositeTransform/>
        </local:ChildView1.RenderTransform>
        </local:ChildView1>
    </Grid>
</phone:PhoneApplicationPage>      

MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    public ICommand ButtonChecked { get; private set; }

    public MainViewModel()
    {
        ButtonChecked = new RelayCommand(() => SwitchVisibility()); 
    }

    public void SwitchVisibility()
    {
        CanShowView = !CanShowView;
        RaisePropertyChanged("CanShowView");
    }

    bool _canShowView = true;
    public bool CanShowView
    {
        get { return _canShowView; }
        set
        {
            if (value != _canShowView)
            {
                _canShowView = value;
                RaisePropertyChanged("CanShowView");
            }
        }
    }

}

ChildView1.xaml:

<UserControl x:Class="myApp.Views.ChildView1"
....
DataContext="{Binding Child1VM, Source={StaticResource Locator}}"
>

    <Grid x:Name="HomeGrid">
        <Button x:Name=myCloseButton Command="{Binding Child1VM.CloseChildViewCmd, Source={StaticResource Locator}}"/>
        ...
    </Grid>
</UserControl>

Child1ViewModel.cs:

namespace myApp
{
    public class Child1ViewModel : ViewModelBase
    {
        public ICommand CloseChildViewCmd { get; private set; }
        public Child1ViewModel()
        {
            CloseChildViewCmd = new RelayCommand(() => ExecuteCloseChildViewCmd());
        }

        public void ExecuteCloseChildViewCmd()
        {
            MainPage mainPage = new MainPage();
            MainViewModel mainVM = new MainViewModel();
            mainPage.DataContext = mainVM;
            mainVM.SwitchVisibility();

        }
    }
}

注意:我只是一个初学程序员,所以我处理问题或程序本身的方式可能有问题,因此我对任何建议持开放态度,并且非常欢迎代码示例。在经过大量研究和试验许多似乎无法发挥作用的事情之后,我已经坚持了很多天这个问题。我花时间详细地写了这个问题,我真的希望能在这里找到解决方案。如果您需要了解更多细节,请与我们联系。 提前谢谢。

编辑:我读过创建视图的新实例不是解决方案。我怎样才能获取MainView的函数并获取属性?

编辑:正如OmegaMan所建议的,我使用静态定义来调用我的函数。 所以更新了MainViewModel.cs:     公共类MainViewModel:ViewModelBase     {         public ICommand ButtonChecked {get;私人集; }         private static MainViewModel Primary {get;组; }

    public MainViewModel()
    {
        ButtonChecked = new RelayCommand(() => SwitchVisibility()); 
        Primary = this;
    }

    public void SwitchVisibility()
    {
        CanShowView = !CanShowView;
        RaisePropertyChanged("CanShowView");
    }

    public static void SwitchViewStatic()
    {
        Primary.SwitchVisibility();
    }

    bool _canShowView = true;
    public bool CanShowView
    {
        get { return _canShowView; }
        set
        {
            if (value != _canShowView)
            {
                _canShowView = value;
                RaisePropertyChanged("CanShowView");
            }
        }
    }

}

更新后的Child1ViewModel.cs:     命名空间myApp     {         公共类Child1ViewModel:ViewModelBase         {             public ICommand CloseChildViewCmd {get;私人集; }             public Child1ViewModel()             {                 CloseChildViewCmd = new RelayCommand(()=&gt; ExecuteCloseChildViewCmd());             }

        public void ExecuteCloseChildViewCmd()
        {
            MainViewModel.SwitchViewStatic();

        }
    }
}

MainViewModel中的所需函数由myCloseButton从子视图调用,但CanShowView仍然不会被引发以允许DataStateBehavior收听它,更新UI ...所以我仍然在impass。

2 个答案:

答案 0 :(得分:1)

问题是您正在向新的MainPage对象发送消息并查看模型,而不是现有的。

您需要的是代表或活动。诀窍是将主页面连接到子页面。

如果您需要将它们分开,则需要一个对象来发送事件。这称为事件聚合器或信使。您的主视图模型需要订阅子视图模型在执行命令时将发送的CloseChild事件。事件聚合器传输消息。

注意:大多数MVVM框架实现了视图模型可用于发送和接收消息/事件的某种信使。

如果您想自己实现一个,请查看here以创建一个。

答案 1 :(得分:1)

让孩子们持有对主视图模型的引用没有错,但为什么控件会创建一个新的MainViewModel?传入MainViewModel并从中调用SwitchVisibility ...或在MainVM上创建一个静态方法,该方法将访问实际VM并调用实例SwitchVisiblity。

---更新以显示来自MainVM的静态方法访问

public class MainViewModel : ViewModelBase
{
    private static MainViewModel Primary { get; set; }

    public MainViewModel()
    {
        Primary = this;
    }

    public static void SwitchViewStatic()
    {
        Primary.SwitchVisibility();
    }

    public void SwitchVisibility()
    {
    ...
    }

}