页面导航后 WPF MVVM 数据绑定中断

Posted

技术标签:

【中文标题】页面导航后 WPF MVVM 数据绑定中断【英文标题】:WPF MVVM data binding broken after page navigation 【发布时间】:2011-04-07 02:51:31 【问题描述】:

我在 WPF 导航样式应用程序中有一个页面,用于显示搜索结果。该页面包含几个数据绑定控件。页面本身工作正常;它执行搜索并返回结果。数据绑定的 CheckBox 控件正常工作。

但如果我单击结果链接,然后单击返回按钮返回结果列表,我的所有CheckBox.IsChecked 数据绑定都将被破坏。其他数据绑定控件(ComboBoxes、DatePickers 等)继续按预期工作。绑定到 CheckBox 控件上的其他属性(如 IsEnabled)可以正常工作。但在我刷新页面之前,IsChecked 绑定仍然断开。

这是用于我的 CheckBox 控件之一的 XAML:

<CheckBox IsChecked="Binding IncludeNote" Content="Note" IsEnabled="Binding IsBusy, Converter=StaticResource boolNot" />

如您所见,这里没有什么特别之处。但是在 WPF 应用程序向前或向后导航到页面后,IsChecked 绑定将被破坏,而IsEnabled 属性将继续工作。

这里发生了什么?这是一个错误吗?

更新:在尝试了一些替代方案后,我发现这个问题也会影响到 CheckBox 派生的 ToggleButton 控件。

UPDATE2: TextBox.Text 属性也损坏了。

有没有办法“刷新”这些控件的数据绑定?还是应该采取其他方法来解决此问题?

【问题讨论】:

【参考方案1】:

显然,它一个错误。这是关于 Microsoft Connect 的错误报告: Binding does not work after back / forward navigation.

报告错误的用户RQDQ也提到了他处理问题的方法:

我发现的解决方法是在 Loaded 事件期间为页面中的所有绑定手动调用 BindingOperations.SetBinding。无论是显式导航还是通过历史记录(后退/前进操作),这似乎都有效。

这只是 WPF4 中的一个问题。数据绑定在 .NET 3.5 中按预期工作。

我希望微软能尽快解决这个问题。对于导航风格的 WPF 应用程序来说,这是一个严重的问题。

【讨论】:

【参考方案2】:

一个简单的解决方法是将 KeepAlive 设置为 true,然后确保 VIewModel 在前一页加载时状态不佳,每次在 Loaded 事件中将 DataContext 设置为一个新实例(即不绑定到您的 Page.Resources 字典中的 ViewModel 实例,例如,因为它将被持久化)。

我们用于将页面绑定到视图模型的标准方法是将简单的行为附加到页面。

public sealed class PageViewModelBehavior : Behavior<Page>

    public Type DataType  get; set; 

    protected override void OnAttached()
    
        this.AssociatedObject.KeepAlive = true;
        this.AssociatedObject.Loaded += this.AssociatedObjectLoaded;
        this.AssociatedObject.Unloaded += this.AssociatedObjectUnloaded;
        base.OnAttached();
    

    protected override void OnDetaching()
    
        this.AssociatedObject.Unloaded -= this.AssociatedObjectUnloaded;
        this.AssociatedObject.Loaded -= this.AssociatedObjectLoaded;
        base.OnDetaching();
    

    private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
    
        if (this.DataType == null || !typeof(IPageViewModel).IsAssignableFrom(this.DataType))
        
            throw new InvalidOperationException("PageViewModelBehavior.DataType is not set. Page: " + this.AssociatedObject.GetType().Name);
        

        this.AssociatedObject.DataContext = Activator.CreateInstance(this.DataType);

        // TODO: Call load on your page view model etc.
    


    private void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
    
        // TODO: Call unload on your page view model etc.

        // Allow the throw-away view model to be GC'd
        this.AssociatedObject.DataContext = null;
    

这可确保每次用户导航回页面时再次绑定页面。这也允许您使用自己喜欢的 IOC 容器来创建 ViewModel。

【讨论】:

这里最大的问题是它会很快导致内存泄漏。

以上是关于页面导航后 WPF MVVM 数据绑定中断的主要内容,如果未能解决你的问题,请参考以下文章

WPF使用MVVM设计模式 问题

在 WPF MVVM Light 中多次绑定到 RelayCommand

我们一起写框架MVVM的WPF框架之绑定

WPF MVVM从入门到精通3:数据绑定

WPF MVVM--数据绑定

WPF MVVM--数据绑定