WPF MVVM页面导航后数据绑定出现问题

5
我在一个WPF导航式应用程序中有一个页面,用于显示搜索结果。该页面包含多个数据绑定控件。页面本身运行良好;它执行搜索并返回结果。数据绑定的复选框控件正常工作。
但是,如果我单击结果链接,然后单击返回按钮返回到结果列表,则所有我的CheckBox.IsChecked数据绑定都会断开连接。其他数据绑定控件(ComboBoxes、DatePickers等)仍然按预期工作。绑定到CheckBox控件上的其他属性,如IsEnabled,正常工作。但是,IsChecked绑定仍然无法正常工作,直到我刷新页面。
以下是我其中一个CheckBox控件使用的XAML代码:
<CheckBox IsChecked="{Binding IncludeNote}" Content="Note" IsEnabled="{Binding IsBusy, Converter={StaticResource boolNot}}" />

正如您所见,这里没有什么花哨的东西。但是,在前进或后退到页面的WPF应用程序中导航后,IsChecked绑定将被破坏,而IsEnabled属性将继续工作。发生了什么?这是一个错误吗?
更新:在尝试了一些替代方案后,我发现这个问题也影响到ToggleButton控件,它从CheckBox派生而来。
更新2:对于TextBox.Text属性也存在同样的问题。是否有一种方法可以“刷新”这些控件的数据绑定?还是我应该采取其他方法来解决这个问题?
2个回答

5

显然,这是一个bug。以下是在Microsoft Connect上的错误报告:后退/前进导航后绑定不起作用

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

我发现的解决方法是在Loaded事件期间手动调用所有页面中的绑定的BindingOperations.SetBinding。这似乎可以在明确导航或通过历史记录(后退/前进操作)进行导航时工作。

这仅适用于WPF4。数据绑定在.NET 3.5中按预期工作。

希望微软能够快速修复此问题。对于基于导航的WPF应用程序来说,这是一个严重的问题。


0
一个简单的解决方法是将KeepAlive设置为true,然后为了确保ViewModel没有因前一页加载而处于错误状态,在Loaded事件中每次都将DataContext设置为一个新实例(例如,请勿将ViewModel实例绑定到您的Page.Resources字典中,因为它会被保留)。
我们用于将页面绑定到view model的标准方法是通过附加到页面的简单行为。
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。


这里最大的问题是它很容易导致内存泄漏。 - ouflak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接