[英]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.任何建议将不胜感激。
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 事件OnNavigated
或OnNavigating
来完成您想要实现的目标。
FlyoutContentTemplateViewModel
in roder to call the method ExecuteLoadFlightsCommand()
from there.FlyoutContentTemplateViewModel
中的 FlyoutContentTemplateViewModel 实例,以便从那里调用方法ExecuteLoadFlightsCommand()
。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;
}
If you don't want to store your VM in your AppShell then you might use DependencyService .如果您不想将 VM 存储在 AppShell 中,那么您可以使用DependencyService 。
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();
}
public FlyoutContentTemplate()
{
InitializeComponent();
BindingContext = viewModel = new FlyoutContentTemplateViewModel();
DependencyService.RegisterSingleton<IFlyoutContentTemplateViewModel>(viewModel);
}
...
if (previousRouteString != null && previousRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]") &&
currentRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]"))
{
DependencyService.Resolve<IFlyoutContentTemplateViewModel>()?.ExecuteLoadFlightsCommand();
}
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.