【问题标题】:RaisePropertyChanged not firing when function called from another viewmodel从另一个视图模型调用函数时,RaisePropertyChanged 不会触发
【发布时间】:2013-10-14 17:54:35
【问题描述】:

我在更新我正在使用的 windows phone 7 应用程序的界面时遇到问题。

我有一个MainPage.xaml 和它的MainViewModel.cs,它们处理子视图用户控件ChildView1.xaml 如何出现在MainPage 中。 ChildView1 也有它的 ViewModel,它是Child1ViewModel.cs。基本上 myToggleButton 会从 MainPage 触发,这将触发 DataStateBehavior 进入显示或隐藏状态以分别显示或隐藏 ChildView1.xaml。 DataStateBehavior 绑定到布尔值CanShowView,而myToggleButton 绑定到名为ButtonCheckedIcommand,它具有中继函数SwitchVisibility,它将反转CanShowView 布尔值以显示或隐藏视图。多亏了我使用的 MVVM 灯的RaisePropertyChanged,一切运行良好。

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

这是我的代码。 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 { 公共 ICommand ButtonChecked { 获取;私人套装; } 私有静态 MainViewModel Primary { 获取;放; }

    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 { 公共 ICommand CloseChildViewCmd { 获取;私人套装; } 公共 Child1ViewModel() { CloseChildViewCmd = new RelayCommand(() => ExecuteCloseChildViewCmd()); }

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

        }
    }
}

MyCloseButton 从子视图调用 MainViewModel 中所需的函数,但 CanShowView 仍然不会被提升以允许 DataStateBehavior 监听它,更新 UI...所以我仍然处于僵局。

【问题讨论】:

  • 你使用的是哪个 mvvm 框架?

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


【解决方案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()
    {
    ...
    }

}

【讨论】:

  • 是的,这似乎确实是错误的。就像我对 McGarnagle 说的那样,我想我在某处读到它会调用应用程序的最新状态。在我之前的尝试中,我没有实例化视图并且仍然无法提升属性。对于静态方法,您的意思是我可以创建例如 public static void LaunchSwitcher(){ SwitchVisibility();} 并从子视图调用该方法?如果是这样,我将如何在不实例化主视图的情况下从该子视图模型调用该方法,或者这无关紧要?感谢您的回复。
  • @JNate 对于静态方法的想法,让VM的构造函数将自己填充到一个静态变量(this实例)中。然后让静态方法使用该静态变量并调用 SwitchVisibility。
  • 我查看了在哪里创建静态变量以存储 MainViewModel 但没有运气。你的意思是像 public static var myVar = this 这样在 MainViewModel 中定义吗?我试图定义它,但我在 var 和 this 上收到错误消息。在这一点上,我应该定义它。这就是你所说的调用 MainViewModel 的静态变量的意思吗?如果我能够创建 myVar,我相信这是应该做的:public static void LaunchSwitcher(){ myVar.SwitchVisibility();} 正确?
  • 如果你能更新我的 MainViewModel 代码,这样我就可以更好地看到要定义的地方,那就太好了。或者至少是你的答案。
  • @JNate 下面是示例...只需在代码中的任意位置调用 MainViewModel.SwitchViewStatic() 即可更新。
【解决方案2】:

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

您需要的是委托或事件。诀窍是将主页面连接到子页面。

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

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

如果您想自己实现一个,请查看here 了解创建方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    相关资源
    最近更新 更多