Xamarin Forms - 如何使用 Viewmodels 将数据从模态页面传回父页面
Xamarin Forms - How to pass data from a modal page back to parent page using Viewmodels
我有两个页面:MainPage
和 FilterPage
(模式页面)。
及其各自的视图模型:MainViewModel
和 FilterViewModel
.
在 MainPage
中,我有一个列表视图,其中填充了来自 API 的数据。数据被传递到 FilterPage
,在那里它被一些特定的标准过滤。最后创建一个新列表,并将其分配给列表视图的绑定变量。我注意到的是,在模式页面关闭后,列表视图的项目没有更新。执行此操作的正确方法是什么?
Model
:
public class Multilist
{
public string Title { get; set; }
public string Date { get; set; }
public string Status { get; set; }
public string Customer { get; set; }
}
MainViewModel
:
public class MainViewModel : INotifyPropertyChanged
{
private IList<Multilist> mainList = new List<Multilist>();
public IList<Multilist> MainList
{
get => mainList;
set
{
if (value == mainList)
return;
mainList = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public MainViewModel(INavigation navigation)
{
this._navigation = navigation;
Task.Run(async () => await GetData());
GotoFilterPageCommand = new AsyncCommand(GotoFilterPage);
}
private async Task GetData()
{
//Gets data from API
MainList = data;
}
private async Task GotoFilterPage()
{
await this._navigation.PushModalAsync(new FilterPage(MainList.ToList()), true);
}
}
FilterViewModel
:
public class FilterViewModel : INotifyPropertyChange
{
public List<Multilist> OldList { get; set; }
private IList<Multilist> mainList = new List<Multilist>();
public IList<Multilist> MainList
{
get => mainList;
set
{
if (value == mainList)
return;
mainList = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public FilterViewModel(List<Multilist> oldlist)
{
Oldlist = oldlist;
SomeCommand = new AsyncCommand(SomeTask);
}
private async Task SomeTask()
{
// Some code here
CreateNewList(OldList);
}
private async Task CreateNewList(List<Multilist> oldlist)
{
//Some code here --> newMainList
pageA.MainList = newMainList;
await App.Current.MainPage.Navigation.PopModalAsync();
}
}
MainPage
中的listview:
<ListView x:Name="TestListView"
ItemsSource="{Binding MainList}"
Grid.Row="4" Grid.ColumnSpan="3"
HasUnevenRows="True"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="0,0,0,1">
<Grid VerticalOptions="Fill" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="{Binding Title}" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Date}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="1" />
<Label Text="{Binding Customer}" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="2" />
<Label Text="{Binding Status}" HorizontalTextAlignment="End" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="3" />
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
您可以使用 Singleton 为 MainViewModel
和 FilterViewModel
创建一个全局实例。
我做一个简单的例子供大家参考
型号:
public class Person
{
public string Name { get; set; }
public string FirstName { get; set; }
public int Age { get; set; }
}
视图模型:
public class PersonViewModel
{
#region Singleton Pattern
private PersonViewModel()
{
Persons = new ObservableCollection<Person>()
{
new Person(){ Name="A"},
new Person(){ Name="A2"},
new Person(){ Name="A3"},
new Person(){ Name="A4"},
};
}
public static PersonViewModel Instance { get; } = new PersonViewModel();
#endregion
private ObservableCollection<Person> _person;
public ObservableCollection<Person> Persons
{
get { return _person; }
set { _person = value; }
}
}
第 24 页://主页
<StackLayout>
<ListView ItemsSource="{Binding MainList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Navigate To FilterPage" Clicked="Button_Clicked">
</Button>
</StackLayout>
第24页后面的代码:
public Page24()
{
InitializeComponent();
this.BindingContext = new Page24ViewModel();
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new FilterPage());
}
Page24ViewModel://MainViewModel
public class Page24ViewModel : INotifyPropertyChanged
{
private PersonViewModel _personViewModel;
public Page24ViewModel()
{
_personViewModel = PersonViewModel.Instance;
}
private ObservableCollection<Person> mainList;
public ObservableCollection<Person> MainList
{
get { return _personViewModel.Persons; }
set
{
mainList = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
筛选页面:
<ContentPage.Content>
<StackLayout>
<StackLayout>
<Label Text="Name:"></Label>
<Entry x:Name="entry"></Entry>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Button x:Name="btn_Add" Text="Add" Clicked="btn_Add_Clicked"></Button>
<!--<Button x:Name="btn_Delete" Text="Delete" Clicked="btn_Delete_Clicked"></Button>-->
</StackLayout>
<ListView ItemsSource="{Binding MainList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
FilterPage后面的代码:
private PersonViewModel _personViewModel;
public FilterPage()//modal page
{
InitializeComponent();
this.BindingContext = new FilterViewModel();
}
private void btn_Add_Clicked(object sender, EventArgs e)
{
_personViewModel = PersonViewModel.Instance;
_personViewModel.Persons.Add(new Person() { Name = entry.Text });
}
过滤器视图模型:
public class FilterViewModel : INotifyPropertyChanged
{
private PersonViewModel _personViewModel;
public FilterViewModel()
{
_personViewModel = PersonViewModel.Instance;
}
private ObservableCollection<Person> newMainList;
public ObservableCollection<Person> MainList
{
get { return _personViewModel.Persons; }
set
{
newMainList = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
我有两个页面:MainPage
和 FilterPage
(模式页面)。
及其各自的视图模型:MainViewModel
和 FilterViewModel
.
在 MainPage
中,我有一个列表视图,其中填充了来自 API 的数据。数据被传递到 FilterPage
,在那里它被一些特定的标准过滤。最后创建一个新列表,并将其分配给列表视图的绑定变量。我注意到的是,在模式页面关闭后,列表视图的项目没有更新。执行此操作的正确方法是什么?
Model
:
public class Multilist
{
public string Title { get; set; }
public string Date { get; set; }
public string Status { get; set; }
public string Customer { get; set; }
}
MainViewModel
:
public class MainViewModel : INotifyPropertyChanged
{
private IList<Multilist> mainList = new List<Multilist>();
public IList<Multilist> MainList
{
get => mainList;
set
{
if (value == mainList)
return;
mainList = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public MainViewModel(INavigation navigation)
{
this._navigation = navigation;
Task.Run(async () => await GetData());
GotoFilterPageCommand = new AsyncCommand(GotoFilterPage);
}
private async Task GetData()
{
//Gets data from API
MainList = data;
}
private async Task GotoFilterPage()
{
await this._navigation.PushModalAsync(new FilterPage(MainList.ToList()), true);
}
}
FilterViewModel
:
public class FilterViewModel : INotifyPropertyChange
{
public List<Multilist> OldList { get; set; }
private IList<Multilist> mainList = new List<Multilist>();
public IList<Multilist> MainList
{
get => mainList;
set
{
if (value == mainList)
return;
mainList = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
public FilterViewModel(List<Multilist> oldlist)
{
Oldlist = oldlist;
SomeCommand = new AsyncCommand(SomeTask);
}
private async Task SomeTask()
{
// Some code here
CreateNewList(OldList);
}
private async Task CreateNewList(List<Multilist> oldlist)
{
//Some code here --> newMainList
pageA.MainList = newMainList;
await App.Current.MainPage.Navigation.PopModalAsync();
}
}
MainPage
中的listview:
<ListView x:Name="TestListView"
ItemsSource="{Binding MainList}"
Grid.Row="4" Grid.ColumnSpan="3"
HasUnevenRows="True"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="0,0,0,1">
<Grid VerticalOptions="Fill" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="{Binding Title}" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Date}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="1" />
<Label Text="{Binding Customer}" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="2" />
<Label Text="{Binding Status}" HorizontalTextAlignment="End" VerticalTextAlignment="Center" Grid.Row="0" Grid.Column="3" />
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
您可以使用 Singleton 为 MainViewModel
和 FilterViewModel
创建一个全局实例。
我做一个简单的例子供大家参考
型号:
public class Person
{
public string Name { get; set; }
public string FirstName { get; set; }
public int Age { get; set; }
}
视图模型:
public class PersonViewModel
{
#region Singleton Pattern
private PersonViewModel()
{
Persons = new ObservableCollection<Person>()
{
new Person(){ Name="A"},
new Person(){ Name="A2"},
new Person(){ Name="A3"},
new Person(){ Name="A4"},
};
}
public static PersonViewModel Instance { get; } = new PersonViewModel();
#endregion
private ObservableCollection<Person> _person;
public ObservableCollection<Person> Persons
{
get { return _person; }
set { _person = value; }
}
}
第 24 页://主页
<StackLayout>
<ListView ItemsSource="{Binding MainList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Navigate To FilterPage" Clicked="Button_Clicked">
</Button>
</StackLayout>
第24页后面的代码:
public Page24()
{
InitializeComponent();
this.BindingContext = new Page24ViewModel();
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new FilterPage());
}
Page24ViewModel://MainViewModel
public class Page24ViewModel : INotifyPropertyChanged
{
private PersonViewModel _personViewModel;
public Page24ViewModel()
{
_personViewModel = PersonViewModel.Instance;
}
private ObservableCollection<Person> mainList;
public ObservableCollection<Person> MainList
{
get { return _personViewModel.Persons; }
set
{
mainList = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
筛选页面:
<ContentPage.Content>
<StackLayout>
<StackLayout>
<Label Text="Name:"></Label>
<Entry x:Name="entry"></Entry>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Button x:Name="btn_Add" Text="Add" Clicked="btn_Add_Clicked"></Button>
<!--<Button x:Name="btn_Delete" Text="Delete" Clicked="btn_Delete_Clicked"></Button>-->
</StackLayout>
<ListView ItemsSource="{Binding MainList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
FilterPage后面的代码:
private PersonViewModel _personViewModel;
public FilterPage()//modal page
{
InitializeComponent();
this.BindingContext = new FilterViewModel();
}
private void btn_Add_Clicked(object sender, EventArgs e)
{
_personViewModel = PersonViewModel.Instance;
_personViewModel.Persons.Add(new Person() { Name = entry.Text });
}
过滤器视图模型:
public class FilterViewModel : INotifyPropertyChanged
{
private PersonViewModel _personViewModel;
public FilterViewModel()
{
_personViewModel = PersonViewModel.Instance;
}
private ObservableCollection<Person> newMainList;
public ObservableCollection<Person> MainList
{
get { return _personViewModel.Persons; }
set
{
newMainList = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}