简体   繁体   English

从我的添加页面导航回来时,如何在我的 FlyoutContentTemplate 视图 model 上触发数据刷新?

[英]How do I trigger a data refresh on my FlyoutContentTemplate view model when navigating back from my add page?

I am building a Xamarin Forms application using Shell in which I am not building your typical flyout.我正在使用 Shell 构建一个 Xamarin Forms 应用程序,其中我没有构建典型的弹出窗口。 I have created a template each for the header, footer and content.我为 header、页脚和内容分别创建了一个模板。 The content contains data which is fetched from a database.内容包含从数据库中获取的数据。

I'm defining these in my app.xaml file.我在我的 app.xaml 文件中定义了这些。

<Style TargetType="Shell" ApplyToDerivedTypes="True">
    <Setter Property="FlyoutFooterTemplate" Value="{DataTemplate common:FlyoutFooterTemplate}"/>
    <Setter Property="FlyoutHeaderTemplate" Value="{DataTemplate common:FlyoutHeaderTemplate}"/>
    <Setter Property="FlyoutContentTemplate" Value="{DataTemplate common:FlyoutContentTemplate}"/>
</Style>

I have created the FlyoutContentTemplate as a RefreshView.我已将 FlyoutContentTemplate 创建为 RefreshView。

<?xml version="1.0" encoding="utf-8" ?>
<RefreshView 
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:InFlight.ViewModels.Common"
    xmlns:model="clr-namespace:InFlight.Core.Models;assembly=InFlight.Core"  
    x:Class="InFlight.Views.Common.FlyoutContentTemplate"
    x:DataType="local:FlyoutContentTemplateViewModel"
    Command="{Binding LoadFlightsCommand}"
    IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
    <CollectionView    
        ItemsSource="{Binding Flights}"
        SelectionMode="None">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <StackLayout Padding="10" x:DataType="model:Flight">
                    <Label Text="{Binding CallSign}"
                            LineBreakMode="NoWrap"
                            Style="{StaticResource LabelMedium}" />
                    <Label Text="{Binding FlightNotes}" 
                            LineBreakMode="NoWrap"
                            Style="{StaticResource LabelSmall}" />
                </StackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
        <CollectionView.Footer>
            <Button Command="{Binding AddFlightCommand}" Text="Add Flight" />
        </CollectionView.Footer>
    </CollectionView>
</RefreshView>

The code behind simply sets the BindingContext.后面的代码只是设置 BindingContext。

using InFlight.ViewModels.Common;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace InFlight.Views.Common
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class FlyoutContentTemplate : RefreshView
    {
        readonly FlyoutContentTemplateViewModel viewModel;

        public FlyoutContentTemplate()
        {
            InitializeComponent();
            this.BindingContext = viewModel = new FlyoutContentTemplateViewModel();
        }
    }
}

The view model is fairly simple and handles the LoadFlightsCommand triggered by the RefreshView and the navigation to the AddEditFlightPage.视图 model 相当简单,它处理由 RefreshView 触发的 LoadFlightsCommand 和到 AddEditFlightPage 的导航。

using InFlight.Core.Models;
using InFlight.Core.Respositories;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace InFlight.ViewModels.Common
{
    public class FlyoutContentTemplateViewModel : BaseViewModel
    {
        public ObservableCollection<Flight> Flights { get; set; }
        public Command LoadFlightsCommand { get; }
        public Command AddFlightCommand { get; }
        readonly IFlightRepository flightRepository;

        public FlyoutContentTemplateViewModel()
        {
            flightRepository = DependencyService.Get<IFlightRepository>();
            
            Flights = new ObservableCollection<Flight>();
            LoadFlightsCommand = new Command(ExecuteLoadFlightsCommand);
            AddFlightCommand = new Command(async () => await OnAddFlightCommand());

            ExecuteLoadFlightsCommand();
        }

        private async Task OnAddFlightCommand()
        {
            await Shell.Current.GoToAsync("AddEditFlightPage");
            Shell.Current.FlyoutIsPresented = false;
        }

        private void ExecuteLoadFlightsCommand()
        {
            IsBusy = true;

            try
            {
                Flights.Clear();
                var flts = flightRepository.GetFlights();

                foreach (var flight in flts)
                {
                    Flights.Add(flight);
                }                
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }
    }
}

This all seems to work well, but at the moment I need to pull to refresh in order to trigger the LoadFlightsCommand .这一切似乎都运作良好,但目前我需要拉动刷新以触发LoadFlightsCommand

The issue is that I want to trigger the data refresh when navigating back from my add page.问题是我想在从我的添加页面导航回来时触发数据刷新。 I've seen posts where people tap into the OnAppearing event in order to trigger the refresh, but as I am using a template and refresh view, I don't see how I can do that.我看到过人们点击OnAppearing事件以触发刷新的帖子,但由于我使用的是模板和刷新视图,所以我不知道该怎么做。

Have I maybe taken the wrong approach and using Shell for a purpose it shouldn't be used for?我是否可能采取了错误的方法并将 Shell 用于不应该用于的目的?

I'm thinking that the solution probably involves the events of the shell itself?我在想解决方案可能涉及 shell 本身的事件?

Any advice would be much appreciated.任何建议将不胜感激。

First Approach第一种方法

I don't have the full picture on how you are defining your Shell 's routes/navigation, but I believe what you are trying to achieve could be done using Shell event OnNavigated or OnNavigating .我不了解您如何定义Shell的路线/导航的全貌,但我相信您可以使用 Shell 事件OnNavigatedOnNavigating来完成您想要实现的目标。

  • First thing, Shell (AppShell.xaml.cs) need to have access to the instance of your FlyoutContentTemplateViewModel in roder to call the method ExecuteLoadFlightsCommand() from there.首先,Shell (AppShell.xaml.cs) 需要访问FlyoutContentTemplateViewModel中的 FlyoutContentTemplateViewModel 实例,以便从那里调用方法ExecuteLoadFlightsCommand()
  • Turn the accessibility of ExecuteLoadFlightsCommand() to public.ExecuteLoadFlightsCommand()的可访问性设置为公开。

AppShell.xaml.cs AppShell.xaml.cs

  public FlyoutContentTemplateViewModel flyoutContentTemplateViewModel;

    public AppShell()
    {
        flyoutContentTemplateViewModel = new();
        InitializeComponent();
    }

  protected override void OnNavigated(ShellNavigatedEventArgs args)
    {
        var previousRouteString = args?.Previous?.Location?.OriginalString;
        var currentRouteString = args?.Current?.Location?.OriginalString;
        
        if (previousRouteString != null && previousRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]") &&
            currentRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]"))
        {
           flyoutContentTemplate.ExecuteLoadFlightsCommand();
        }

        base.OnNavigated(args);
    }

In your FlyoutContentTemplate() , use the same ViewModel instance from the field that we have added in your AppShell.在您的FlyoutContentTemplate()中,使用我们在您的 AppShell 中添加的字段中的相同 ViewModel 实例。

public FlyoutContentTemplate()
{
   InitializeComponent();
   BindingContext = viewModel = (Shell.Current as AppShell).flyoutContentTemplateViewModel;
}

Second Approach第二种方法

If you don't want to store your VM in your AppShell then you might use DependencyService .如果您不想将 VM 存储在 AppShell 中,那么您可以使用DependencyService

  • Extract an interface from your FlyoutContentTemplateViewModel : on visual studio select the class name, right click, in the menu click "Quick Actions and refactoring", after that click "Extract interface", VS will generate an interface called IFlyoutContentTemplateViewModel :FlyoutContentTemplateViewModel中提取一个界面:在 visual studio select 名称 class 上单击鼠标右键,在菜单中单击“快速操作和重构”,然后单击“提取界面”,VS 将生成一个名为IFlyoutContentTemplateViewModel的界面:
 public interface IFlyoutContentTemplateViewModel
    {
        Command AddFlightCommand { get; }
        ObservableCollection<Flight> Flights { get; set; }
        bool IsBusy { get; }
        Command LoadFlightsCommand { get; }

        Task OnAddFlightCommand()
        void ExecuteLoadFlightsCommand();
    }
  • FlyoutContentTemplate.xaml.cs FlyoutContentTemplate.xaml.cs
public FlyoutContentTemplate()
{
    InitializeComponent();
    BindingContext = viewModel = new FlyoutContentTemplateViewModel();
    DependencyService.RegisterSingleton<IFlyoutContentTemplateViewModel>(viewModel);
}
  • AppShell.xaml.cs AppShell.xaml.cs
...
if (previousRouteString != null && previousRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]") &&
    currentRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]"))
 {
        DependencyService.Resolve<IFlyoutContentTemplateViewModel>()?.ExecuteLoadFlightsCommand();
 }

Third Approach第三种方法

Calling ExecuteLoadFlightsCommand() from OnDisappearing() of AddEditFlightPage , instead of AppShell.OnNavigated() .OnDisappearing() AddEditFlightPage调用ExecuteLoadFlightsCommand() ,而不是AppShell.OnNavigated()

AddEditFlightPage.xaml.cs AddEditFlightPage.xaml.cs

    protected override void OnDisappearing()
    {
        (DependencyService.Resolve<IFlyoutContentTemplateViewModel>())?.ExecuteLoadFlightsCommand();
        base.OnDisappearing();
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在POST回我的控制器时,是否必须将部分视图的数据重新分配给模型? - Do I have to reassign a partial view's data back to the model when POSTing back to my controller? 返回视图时如何刷新我的页面 - how to refresh my page when returning a view 如何在我的视图模型中从域服务访问数据? Silverlight 5应用 - How do I access the data from my domain service in my view model ? Silverlight 5 application 如何刷新我的winforms页面? - How do I refresh my winforms page? 如何使用我的视图模型类并将数据从视图模型传递到页面上的视图? - How to use my view model class and passing data from view model to View on the page? 当 API 调用完成时,如何从 .RAZOR 主页面中的所有子组件触发/刷新我的 .RAZOR 主页面? - How can I trigger/refresh my main .RAZOR page from all of its sub-components within that main .RAZOR page when an API call is complete? 在我的数据库中插入和更新我的值后,如何从另一个表单刷新我的数据网格视图? - How do I refresh my datagrid view from another form after I insert and update my values inside my database? 用户确认模型信息后如何回发模型? - How Do I Post Back My Model When User Confirms Model Information? 如何将包含两个列表的模型从视图发送回控制器 - How can i send back a model containing two lists from the view to my controller 如何将数据从我的视图传递到 controller? - How do I pass the data from my View to the controller?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM