Sje*_*oet 5 c# mvvm xamarin xamarin.forms
背景信息
我正在 XAML 中开发 Xamarin Forms(v4.1.1.3,在 iOS 上测试)应用程序,使用 MVVM 和视图优先方法;我使用 MVVMLight 的 ViewModelLocator 服务将单实例 ViewModel 分配给视图:
BindingContext="{Binding [SearchViewModel], Source={StaticResource ViewModelLocator}}"
Run Code Online (Sandbox Code Playgroud)
当导航到另一个页面时,我正在构建该页面的一个新实例,该实例每次都会收到完全相同的 ViewModel 实例。
var page = new SearchView();
var tabbedPage = Application.Current.MainPage as TabbedPage;
if (tabbedPage != null)
await tabbedPage.CurrentPage.Navigation.PushAsync(page);
Run Code Online (Sandbox Code Playgroud)
问题
我已经实现了一个自定义控件(视图?),它应该以类似平铺的布局显示搜索结果。该控件是在从搜索导航NavigationPage
到搜索结果时创建的ContentPage
。
每次我返回搜索页面并导航回搜索结果时,都会重建视图并订阅PropertyChanged
视图。BindableProperties
这些PropertyChanged
事件永远不会取消订阅,因此每次我导航到搜索结果视图并更改绑定的 ViewModel 属性时,该事件都会被触发多次。
在以下代码中OnItemsPropertyChanged
,根据我从搜索视图导航到搜索结果视图的次数,会多次触发:
public class WrapLayout : Grid
{
public static readonly BindableProperty ItemsProperty =
BindableProperty.Create("Items", typeof(IEnumerable), typeof(WrapLayout), null, propertyChanged: OnItemsPropertyChanged);
public IEnumerable Items
{
get { return (IEnumerable)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public WrapLayout()
{
...
}
private static void OnItemsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题:
BindableProperty
取消订阅吗?PropertyChanged
-Changing
编辑; 附加导航信息
我有一个MainView
TabbedPage
,它创建SearchView
为NavigationPage
:
public MainView()
{
InitializeComponent();
Children.Add(new NavigationPage(new SearchView())
{
Title = AppResources.Tab_Search,
Icon = "tab_search"
});
}
Run Code Online (Sandbox Code Playgroud)
SearchView
ViewModelLocator
创建时,有一个由本主题开头提到的使用 MVVMLight容器分配的单实例 ViewModel SimpleIoc
。
当搜索命令被SearchView
触发时,我向返回搜索结果的 API 发送请求。这些结果显示在另一个页面上,我从 的SearchView
ViewModel 导航到该页面:
await _navigationService.NavigateTo(ViewModelLocator.PageKeyFileResults, searchResult);
Run Code Online (Sandbox Code Playgroud)
哪个功能看起来有点像这样:
public async Task NavigateTo(string pagekey, object viewModelParameter)
{
var constructor = _pagesByKey[pagekey].Constructor; //Gets the Func<Page> that simple creates the requested page, without using reflection.
var page = constructor() as Page;
var viewModel = page.BindingContext as BaseViewModel;
if (viewModel != null)
viewModel.Initialize(viewModelParameter);
var tabbedPage = Application.Current.MainPage as TabbedPage;
if (tabbedPage != null)
await tabbedPage.CurrentPage.Navigation.PushAsync(page);
else
await Application.Current.MainPage.Navigation.PushAsync(page);
}
Run Code Online (Sandbox Code Playgroud)
构建的页面看起来有点像:
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Views.FileResultsView"
xmlns:pages="clr-namespace:Views.Pages;assembly=Views"
xmlns:controls="clr-namespace:Views.Controls;assembly=Views"
BindingContext="{Binding [FileResultsViewModel], Source={StaticResource ViewModelLocator}}">
<ScrollView>
<controls:WrapLayout
Items="{Binding SearchResults}" />
</ScrollView>
</pages:BaseContentPage>
Run Code Online (Sandbox Code Playgroud)
其中 BaseContentPage 是:
public class BaseContentPage : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();
MessagingCenter.Subscribe<DialogMessage>(this, "ShowDialog", (dialogMessage) =>
{
if (string.IsNullOrWhiteSpace(dialogMessage.AcceptButton))
DisplayAlert(dialogMessage.Title, dialogMessage.Content, dialogMessage.CancelButton);
else
DisplayAlert(dialogMessage.Title, dialogMessage.Content, dialogMessage.AcceptButton, dialogMessage.CancelButton);
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
MessagingCenter.Unsubscribe<DialogMessage>(this, "ShowDialog");
}
}
Run Code Online (Sandbox Code Playgroud)
ViewModel 基本上是这样的:
public class FileResultsViewModel : BaseViewModel
{
private IEnumerable<ASRow> _searchResults;
public IEnumerable<ASRow> SearchResults
{
get { return _searchResults; }
set { Set(ref _searchResults, value); }
}
internal override void Initialize(object parameter)
{
base.Initialize(parameter);
if (parameter is AdvancedSearchResponse)
{
var searchResults = parameter as AdvancedSearchResponse;
SearchResults = new List<ASRow>(searchResults.Rows);
}
}
}
Run Code Online (Sandbox Code Playgroud)
不,Binding
班级会处理这件事。不是BindableProperty
.
您看到这一点是因为您忘记了导航堆栈在内存中保存了页面列表。由于多个页面指向同一个 BindingContext,因此有多个观察者来观察变化。如果您不重用视图模型,则不会遇到此特定问题。
不会。如果确实有问题,请设置BindingContext
为null
页面消失时,然后在重新出现时恢复它。请记住,这仍然是有成本的,特别是当您的 UI 非常繁忙并且有大量由数据绑定控制的动态内容时。
归档时间: |
|
查看次数: |
960 次 |
最近记录: |