![](/img/trans.png)
[英]How to set BindingContext of multiple pages to the same ViewModel in Xamarin.Forms?
[英]Xamarin Forms - Multiple items in BindingContext in ViewCell
我在 xaml 中有一個“主”頁面,其中包含我的單元格視圖。
<ContentPage.Content>
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
在我的 CellView 中,我想添加 2 個轉換器作為 BindableContext 並將它們集成到我的一些字段中:
<<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OperaMobile.Views.Postlogin"
xmlns:converterFontFamily="clr-namespace:OperaMobile.Converters"
xmlns:converterColor="clr-namespace:OperaMobile.Converters"
mc:Ignorable="d"
x:Class="OperaMobile.ViewCells.ObjectItemViewCell">
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
<ViewCell.View>
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout
Padding="0,10"
Grid.Column="0"
Grid.Row="0"
Margin="15,0"
VerticalOptions="Center"
Orientation="Horizontal">
<Image Source="pin"/>
<Label FontAttributes="Bold" Text="{Binding Label}" Grid.Column="0" Grid.Row="0"/>
</StackLayout>
<StackLayout
Grid.Column="0"
Grid.Row="1"
BindableLayout.ItemsSource="{Binding InfoBox.CountDetailsItemsRows}"
Orientation="Horizontal"
Margin="13,10,0,0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<ListView
Margin="15,0"
Grid.Column="0"
Grid.Row="1"
SeparatorVisibility="None"
HasUnevenRows="True"
IsEnabled="False"
VerticalScrollBarVisibility="Never"
ItemsSource="{Binding InfoBox.DetailsObjectInfos}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Grid.Column="1" Orientation="Horizontal" Padding="0" Spacing="0">
<Label FontAttributes="Bold" Text="{Binding BoldLabelTitle}" Padding="0"/>
<Label Text="{Binding LabelValue}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout VerticalOptions="Start" Grid.Column="1" Grid.RowSpan="2" Spacing="15" Padding="20,10" Orientation="Horizontal" HorizontalOptions="End">
<StackLayout.Resources>
<ResourceDictionary>
<converterColor:BoolToStringConverter
x:Key="colorConverter"
TrueValue="#0275BA"
FalseValue="#949494"/>
<converterFontFamily:BoolToStringConverter
x:Key="fontFamilyConverter"
TrueValue="FA-S"
FalseValue="FA-R"/>
</ResourceDictionary>
</StackLayout.Resources>
<!--"{Binding IsFavorite, Converter={StaticResource fontFamilyConverter}}-->
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueColorStyle}" Text="{StaticResource IconEye}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectDetailsCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
<Label FontSize="Medium" Style="{DynamicResource BlueSolidColorStyle}" Text="{StaticResource IconPin}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ViewObjectOnMapCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</Grid>
</StackLayout>
</ViewCell.View>
</ViewCell>
這是我的主頁的虛擬機,我在其中添加了 viewcell 作為 DataTemplate,所以這里是:
public class SearchObjectsViewModel : BaseViewModel, INotifyPropertyChanged
{
public SearchObjectsViewModel()
{
Task.Run(async () => { await GetObjectInstancesList(); });
ToggleFavoriteObjectCommand = new Command(async(data) => await ToggleFavoriteObjects(data));
ViewObjectDetailsCommand = new Command(async (data) => await GetObjectDetails(data));
ViewObjectOnMapCommand = new Command(async (data) => await ViewObjectOnMap(data));
}
#region Properties
private string searchedText;
public string SearchedText
{
get { return searchedText; }
set
{
SetProperty(ref searchedText, value);
ObjectsSearch(searchedText);
}
}
ObservableCollection<CustomPin> _objectItems { get; set; }
public ObservableCollection<CustomPin> ObjectItems
{
get
{
return _objectItems;
}
set
{
if (_objectItems != value)
{
_objectItems = value;
OnPropertyChanged(nameof(ObjectItems));
}
}
}
#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 ICommand ViewObjectOnMapCommand { get; set; }
public ICommand ViewObjectDetailsCommand { get; set; }
public ICommand ToggleFavoriteObjectCommand { get; set; }
#endregion
#region Methods
private async Task GetObjectInstancesList()
{
ObjectItems = new ObservableCollection<CustomPin>();
var objectsResponse = await ApiServiceProvider.GetObjectInstances();
Device.BeginInvokeOnMainThread(() =>
{
if (objectsResponse.Succeeded)
{
foreach (var item in objectsResponse.ObjectInstances)
{
CustomPin pinData = new CustomPin();
pinData.Id = item.IdObjectInstance;
pinData.Label = item.ObjectClassName;
pinData.IsFavorite = item.IsFavorite.HasValue ? item.IsFavorite.Value : false;
if (item.Points != null)
{
pinData.Position = new Position(item.Points.FirstOrDefault().Latitude, item.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var s in item.Strings)
{
if (s.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = s.ClassParameterName + ": ",
LabelValue = s.StringValue
});
}
}
foreach (var i in item.Integers)
{
if (i.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = i.ClassParameterName + ": ",
LabelValue = i.IntValue.ToString()
});
}
}
foreach (var date in item.Dates)
{
if (date.ShowInBallon)
{
pinData.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo
{
BoldLabelTitle = date.ClassParameterName + ": ",
LabelValue = date.DateValue.ToString()
});
}
}
ObjectItems.Add(pinData);
pinData.InfoBox.CountDetailsItemsRows = pinData.InfoBox.DetailsObjectInfos.Count * 85;
}
}
TemporalData.ObjectsData = ObjectItems;
OnPropertyChanged(nameof(ObjectItems));
OnPropertyChanged(nameof(TemporalData.ObjectsData));
});
}
private void ObjectsSearch(string searchedText)
{
if (!string.IsNullOrWhiteSpace(searchedText))
{
var result = TemporalData.ObjectsData.Where(x => x.Label.ToLowerInvariant().Contains(searchedText.ToLowerInvariant())).ToList();
ObjectItems = new ObservableCollection<CustomPin>(result);
}
else
{
ObjectItems = new ObservableCollection<CustomPin>(TemporalData.ObjectsData);
}
OnPropertyChanged(nameof(ObjectItems));
}
private async Task ViewObjectOnMap(object objectId)
{
CustomPin selectedPin = App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
App.GoToPinCommand = new Command(() => App.GoToPinCommand.Execute(selectedPin));
await Shell.Current.GoToAsync(Routes.MapPage);
}
private async Task GetObjectDetails(object objectId)
{
App.SelectedPin = ObjectItems.Where(x => x.Id == Convert.ToInt32(objectId)).FirstOrDefault();
await Shell.Current.GoToAsync(Routes.ItemDetailsPage);
}
private async Task ToggleFavoriteObjects(object objectId)
{
int id = Convert.ToInt32(objectId);
var objectItem = ObjectItems.Where(x => x.Id == id).FirstOrDefault();
var favoriteToggleResponse = await ApiServiceProvider.ToggleFavoriteObjectById(id, !objectItem.IsFavorite);
if (!favoriteToggleResponse.Succeeded)
{
await Shell.Current.DisplayAlert("Error", "Lost communication with server. Try again.", "OK");
}
else
{
ObjectItems.Where(x => x.Id == id).Select(c => { c.IsFavorite = !c.IsFavorite; return c; }).ToList();
}
}
#endregion
}
我收到錯誤消息: BindingCOntext is set more than once.
我遇到的其他問題是模擬器無法識別 TapGestureRecognizer 例如這個 Label 您可以參考代碼:
<Label FontSize="Medium" FontFamily="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" TextColor="{Binding IsFavorite, Converter={StaticResource Key=fontFamilyConverter}}" Text="{StaticResource IconStar}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand}" CommandParameter="{Binding Id}"/>
</Label.GestureRecognizers>
</Label>
我需要輸入類似Command="{Binding Path=BindingContext.ToggleFavoriteObjectCommand,Source={x:Reference Page}}"
但我不知道在我的情況下是否可以引用“父頁面”它會是“主頁面” " 我調用 cellView 的頁面。
您設置BindingContext
兩次。
第一個:實際上下面的代碼確實在 Cell 上自動設置了 BindingContext,內容是 List ObjectItems
中的項目。
<ListView.ItemTemplate>
<DataTemplate>
<viewcells:ObjectItemViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
第二
<ViewCell.BindingContext>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<!--<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>-->
</ViewCell.BindingContext>
不要在 ViewCell 中設置 BindingContext,如果要使用轉換器,可以直接在頁面中添加。
<ListView
Margin="0,15,0,0"
SelectionMode="None"
RowHeight= "150"
ItemsSource="{Binding ObjectItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell BindingContext="{Binding Converter = {StaticResource fontFamilyConverter}}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
該命令不會觸發,因為綁定路徑不正確,將這些命令放入 model CustomPin
解決問題。
問題是,您在 BindingContext 標記中設置轉換器。 它們需要像這樣設置:
<ContentPage.BindingContext>
YOUR BINDING CONTEXT
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converterFontFamily:BoolToStringConverter x:Key="fontFamilyConverter"/>
<converterColor:BoolToStringConverter x:Key="fontFamilyConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
由於 BindingContext 錯誤,您的命令無法正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.