簡體   English   中英

Xamarin Forms - ViewCell 中 BindingContext 中的多個項目

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM