在Xamarin.Forms中处理对象

时间:2017-04-19 11:31:57

标签: c# xamarin xamarin.forms

我正在寻找在Xamarin Forms应用程序中处理对象的正确方法。目前我正在使用XAML和MVVM编码风格。然后从我的视图模型中,我通过内置服务定位器(DependencyService)获得对一次性对象的引用。理想情况下,我应该可以从我的视图模型中调用对象上的Dispose(),但是附加到ContentPage.OnDisappearingNavigationPage.Popped等其他解决方案也是可行的。

3 个答案:

答案 0 :(得分:4)

几周前,我几乎有同样的要求。我希望确保在关闭页面时取消订阅视图模型中的事件订阅。经过大量研究后,我的结论是最简单的解决方案是使用ContentPage.OnDisappearing方法。

正如您所指出的那样,您要处置的对象位于ViewModel中,因此您需要一些基础结构来确保ViewModel在消失时得到通知。为此,我定义了我的视图模型的基本实现,它有两个关键方法OnAppearing和OnDisappearing(注意这是一个类而不是一个接口,因为我有其他基本功能,如IPropertyNotify实现 - 这里没有显示)。

public class ViewModelBase
{
    /// <summary>
    /// Called when page is appearing.
    /// </summary>
    public virtual void OnAppearing()
    {
        // No default implementation. 
    }

    /// <summary>
    /// Called when the view model is disappearing. View Model clean-up should be performed here.
    /// </summary>
    public virtual void OnDisappearing()
    {
        // No default implementation. 
    }
}

然后我对ContentPage进行了子类化并覆盖OnAppearing和OnDisappearing方法,然后使用它们来通知我的视图模型。

public class PageBase : ContentPage
{
    /// <summary>
    /// Performs page clean-up.
    /// </summary>
    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        var viewModel = BindingContext as ViewModelBase;

        // Inform the view model that it is disappearing so that it can remove event handlers
        // and perform any other clean-up required..
        viewModel?.OnDisappearing();
    }

    protected override void OnAppearing()
    {
        // Inform the view model that it is appearing
        var viewModel = BindingContext as ViewModelBase;

        // Inform the view model that it is appearing.
        viewModel?.OnAppearing();
    }
}

然后,当您实现页面时,请确保它的类型为PageBase:

<?xml version="1.0" encoding="utf-8" ?>
<pages:PageBase xmlns="http://xamarin.com/schemas/2014/forms"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          xmlns:controls="clr-namespace:Forms.App.Controls;assembly=Forms.App"
          xmlns:converters="clr-namespace:Forms.App.Converters;assembly=Forms.App"
          xmlns:pages="clr-namespace:Forms.App.Pages;assembly=Forms.App"
          x:Class="Forms.App.Pages.LogonPage"
          NavigationPage.HasNavigationBar="False"
          Title="Logon">

然后在ViewModel中,您可以覆盖OnDisappearing方法并处理对象:

public class FormViewModel : ViewModelBase
{
    public override void OnDisappearing()
    {
        base.OnDisappearing();

        // Dispose whatever objects are neede here
    }
}

只需注意一件事 - 如果您正在使用堆栈导航,当您在当前页面上堆叠另一个页面时,会调用OnDisappearing方法(您的页面毕竟会暂时消失)。因此,您需要满足此要求,并且在这种情况下可能不会丢弃您的对象。但是,如果您没有在页面顶部堆叠任何内容,则无需担心。在我的例子中,它只是事件订阅,所以我在OnAppearing中附加事件处理程序并在OnDisappearing上分离它们。

我希望能帮到你!

答案 1 :(得分:4)

当ListViews或Labels的绑定在处理页面/片段时更改了值时,我们在Forms中处理了对象异常。我假设你可以在我们移除绑定的同一个地方处理ViewModel中的对象。

protected override void OnParentSet()
{
    base.OnParentSet();

    if (Parent == null)
    {
        //Clear a bunch of bindings or dispose of ViewModel objects 
        BindingContext =
            _listView.ItemsSource = null;
    }
}

答案 2 :(得分:1)

我有符合IDisposable的View模型。所以我需要一种方法来在不再需要页面时处理Page的BindingContext。

我使用了Nick的建议,当不再需要页面时,使用OnParentSet将其设置为NULL。

可以使用SafeContentPage类代替ContentPage。 Iff绑定上下文支持IDisposable它会自动尝试处理绑定上下文。

public class SafeContentPage : ContentPage
{
    protected override void OnParentSet()
    {
        base.OnParentSet();
        if (Parent == null)
            DisposeBindingContext();
    }

    protected void DisposeBindingContext()
    {
        if (BindingContext is IDisposable disposableBindingContext) {
            disposableBindingContext.Dispose();
            BindingContext = null;
        }
    }

    ~SafeContentPage()
    {
        DisposeBindingContext();
    }
}

OnDisappearing方法不是一种可靠的技术,因为在调用它时存在平台差异,并且仅仅因为页面消失并不意味着不再需要它的视图模型。