0
votes

I am having issues with displaying data, I can see my data FieldValue and FieldDescriptor in the List property however I still see in output that:

Binding: 'Results' property not found on 'ViewModel.ResultPageViewModel', target property: 'Xamarin.Forms.ListView.ItemsSource'

I can't see any data FieldVisualData in the horizontal list view even thought I can see them in the view model adding to detail and the command also can't be found.

Binding: 'EditTextCommand' property not found on 'Model.DocumentData', target property: 'Xamarin.Forms.TapGestureRecognizer.Command'

Maybe you see something that I am missing?

 <StackLayout Spacing="0">
                <!--Pictures-->
        <StackLayout VerticalOptions="Start" Spacing="0" >  
               <controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView"  ItemsSource="{Binding Results, Mode=TwoWay}">
                    <controls:HorizontalScrollList.ItemTemplate>
                        <DataTemplate>
                            <Image Source="{Binding Results.FieldVisualData}" 
                                    Margin="5">
                                <!--<Image.GestureRecognizers>
                                    <TapGestureRecognizer
                                        Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
                                        CommandParameter="{Binding}"/>
                                </Image.GestureRecognizers>-->
                            </Image>
                        </DataTemplate>
                    </controls:HorizontalScrollList.ItemTemplate>
                </controls:HorizontalScrollList>                          
        </StackLayout>
            
        <StackLayout  VerticalOptions="Start" BackgroundColor="{DynamicResource SeparatorLineColor}" Spacing="10">
              <!--DocumentData-->
             <Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
            <StackLayout BackgroundColor="{DynamicResource PageBackgroundColor}"  VerticalOptions="FillAndExpand">
                <ListView x:Name="list" BackgroundColor="{DynamicResource PageBackgroundColor}"
                    HasUnevenRows="True"
                    HorizontalOptions="CenterAndExpand"
                    VerticalOptions="CenterAndExpand"
                    VerticalScrollBarVisibility="Never"
                    CachingStrategy="RecycleElement"
                   ItemsSource="{Binding Results, Mode=TwoWay}"
                    SeparatorVisibility="Default"
                    SelectionMode="None">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                        <ViewCell>
                                <Grid  BackgroundColor="{DynamicResource PageBackgroundColor}" Padding="10" >
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="15*"/>
                                         <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="12*"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                   <Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" Style="{StaticResource SubLabelBlackStyle}" HorizontalOptions="Start" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalTextAlignment="Start"/>
                                   <Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3"  BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalOptions="Start" HorizontalTextAlignment="Start">
                                       <Label.GestureRecognizers>
                                           <TapGestureRecognizer Command="{Binding EditTextCommand}"  CommandParameter="{Binding FieldValue}" />
                                       </Label.GestureRecognizers>
                                   </Label>
                              </Grid>
                        </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>
        </StackLayout>    
</StackLayout>
public partial class ResultPage : ContentPage
{
    public ResultPage(IEnumerable<DocumentData> data)
    {
      InitializeComponent();
      BindingContext = new ResultPageViewModel(data);

       //carouselView.ItemsSource = data;
       // list.ItemsSource = data;
     
    }
}

public class ResultPageViewModel : BaseViewModel
{
    public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
    public ICommand EditTextCommand { get; }
    object param = "";
    public ResultPageViewModel(IEnumerable<DocumentData> data)
    {
        EditTextCommand = new Command(async () => await EditTextAsync(param));
        Load(data);
    }

    public void Load(IEnumerable<DocumentData> data)
    {
        foreach (var result in data)
        {
            var detail = new DocumentData()
            {
                FieldVisualData = result.FieldVisualData,
                FieldDescriptor = result.FieldDescriptor,
                FieldValue = result.FieldValue,
            };
            Results.Add(detail);
          
        }
    }

    public async Task EditTextAsync(object param)
    {
        PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
        {
            InputType = InputType.Password,
            Text = param.ToString(),
            Title = Resources.AppResources.Password_lbl,
        });
    }
}

public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create( "ItemTemplate", typeof(DataTemplate), typeof(HorizontalScrollList), null, propertyChanged: (bindable, value, newValue) => ((HorizontalScrollList)bindable).Populate());

    public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
        "ItemsSource",
        typeof(IEnumerable),
        typeof(HorizontalScrollList),
        null,
        BindingMode.OneWay,
        propertyChanged: (bindable, value, newValue) =>
        {
            var obs = value as INotifyCollectionChanged;
            var self = (HorizontalScrollList)bindable;
            if (obs != null)
                obs.CollectionChanged -= self.HandleItemChanged;

            self.Populate();

            obs = newValue as INotifyCollectionChanged;
            if (obs != null)
                obs.CollectionChanged += self.HandleItemChanged;
        });

    public IEnumerable ItemsSource
    {
        get => (IEnumerable)this.GetValue(ItemsSourceProperty);
        set => this.SetValue(ItemsSourceProperty, value);
    }

    public DataTemplate ItemTemplate
    {
        get => (DataTemplate)this.GetValue(ItemTemplateProperty);
        set => this.SetValue(ItemTemplateProperty, value);
    }

    private bool willUpdate = true;
    private void HandleItemChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
    {
        if (!willUpdate)
        {
            willUpdate = true;
            Device.BeginInvokeOnMainThread(Populate);
        }
    }

    public HorizontalScrollList()
    {
        this.Orientation = ScrollOrientation.Horizontal;
    }

    private void Populate()
    {
        willUpdate = false;

        Content = null;

        if (ItemsSource == null || ItemTemplate == null)
        {
            return;
        }

        var list = new StackLayout { Orientation = StackOrientation.Horizontal };

        foreach (var viewModel in ItemsSource)
        {
            var content = ItemTemplate.CreateContent();
            if (!(content is View) && !(content is ViewCell))
            {
                throw new Exception($"Invalid visual object {nameof(content)}");
            }

            var view = content is View ? content as View : ((ViewCell)content).View;
            view.BindingContext = viewModel;

            list.Children.Add(view);
        }

        if (list.Children.Count == 0)
        {
            list.Padding = 20;
            list.Children.Add(new Label
            {
                WidthRequest = (list as VisualElement).Width - 30,
                HorizontalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
                VerticalOptions = new LayoutOptions(LayoutAlignment.Fill, true),
                HorizontalTextAlignment = TextAlignment.Center,
                VerticalTextAlignment = TextAlignment.Center,
                FontSize = 15,
               
            });
        }

        Content = list;
    }
1
EditTextCommand is a property of the VM, not DocumentData. Each row in the LIstView is bound to a DocumentData object. If you want to reference a property on the parent VM, see docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/…Jason
based on your description its very difficult to determine which data IS working and which is NOT. Please edit your question to make it clearer which specific elements are causing problemsJason

1 Answers

0
votes

Do you want to acheve the result like following GIF?

enter image description here

I do not which style or backgroundcolor that you setted, I set it with static background color.

Here is my editted layout.controls:HorizontalScrollList is a picture, so I comment it.

I change the Command in the TapGestureRecognizer

 <StackLayout Spacing="0">
        <!--Pictures-->
        <StackLayout VerticalOptions="Start" Spacing="0" >
            <!--<controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView"  ItemsSource="{Binding Results, Mode=TwoWay}">
                <controls:HorizontalScrollList.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Results.FieldVisualData}" 
                                    Margin="5">
                            --><!--<Image.GestureRecognizers>
                                    <TapGestureRecognizer
                                        Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
                                        CommandParameter="{Binding}"/>
                                </Image.GestureRecognizers>--><!--
                        </Image>
                    </DataTemplate>
                </controls:HorizontalScrollList.ItemTemplate>
            </controls:HorizontalScrollList>-->
        </StackLayout>

        <StackLayout  VerticalOptions="Start" BackgroundColor="White" Spacing="10">
            <!--DocumentData-->
            <Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
            <StackLayout BackgroundColor="Green"  VerticalOptions="FillAndExpand">
                <ListView x:Name="list" BackgroundColor="Red"
                    HasUnevenRows="True"
                    HorizontalOptions="CenterAndExpand"
                    VerticalOptions="CenterAndExpand"
                    VerticalScrollBarVisibility="Never"
                    CachingStrategy="RecycleElement"
                   ItemsSource="{Binding Results, Mode=TwoWay}"
                    SeparatorVisibility="Default"
                    SelectionMode="None">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Grid  BackgroundColor="Beige" Padding="10" >
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="15*"/>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="12*"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
                                    <Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3"  BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
                                        <Label.GestureRecognizers>
                                            <TapGestureRecognizer
                                                Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"  
                                                CommandParameter="{Binding .}"
                                                
                                                
                                                />
                                        </Label.GestureRecognizers>
                                    </Label>
                                </Grid>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>
        </StackLayout>
    </StackLayout>

Here is layout background code. I add three data to make a test.

 public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData=1 } };
            data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = 2 });
            data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = 3 });

            this.BindingContext = new ResultPageViewModel(data);
        }
    }

Here is ResultPageViewModels code.

using Acr.UserDialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace XFormsListviewMvvm
{
    public class ResultPageViewModel : BaseViewModel
    {
        public ObservableCollection<DocumentData> Results { get; } = new ObservableCollection<DocumentData>();
        public ICommand EditTextCommand { get; }
        object param = "";
        public ResultPageViewModel(IEnumerable<DocumentData> data)
        {
            EditTextCommand = new Command<DocumentData>(async (key) => await EditTextAsync(key));
            Load(data);
        }

        public void Load(IEnumerable<DocumentData> data)
        {
            foreach (var result in data)
            {
                var detail = new DocumentData()
                {
                    FieldVisualData = result.FieldVisualData,
                    FieldDescriptor = result.FieldDescriptor,
                    FieldValue = result.FieldValue,
                };
                Results.Add(detail);

            }
        }

        public async Task EditTextAsync(DocumentData param)
        {
            PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
            {
                InputType = InputType.Password,
                Text = param.FieldValue.ToString(),
                Title = "Insert your Password",
            });
            if (pResult.Ok)
            {
                param.FieldValue = pResult.Text;
            }
          
        }
    }
}

If you need to change the value, then layout will display it. you need to implement the BaseViewModel in the DocumentData.

namespace XFormsListviewMvvm
{
    public class DocumentData:BaseViewModel
    {
    

        private object fieldVisualData = "Hello world";
        public object FieldVisualData
        {
            get => fieldVisualData;
            set => SetValue(ref fieldVisualData, value);
        }

        private object fieldValue = "Hello world";
        public object FieldValue
        {
            get => fieldValue;
            set => SetValue(ref fieldValue, value);
        }
        public object FieldDescriptor { get; internal set; }
    
    }
}

=============Update===================

I add your controls:HorizontalScrollList code. And I change the from <Image Source="{Binding Results.FieldVisualData}"> to <Image Source="{Binding FieldVisualData}" >

Here is running gif.Image could be seen normally.

enter image description here

Here is editted layout.

 <StackLayout Spacing="0">
        <!--Pictures-->
        <StackLayout VerticalOptions="Start" Spacing="0" >
            <controls:HorizontalScrollList VerticalOptions="Start" HeightRequest="300" x:Name="carouselView"  ItemsSource="{Binding Results, Mode=TwoWay}">
                <controls:HorizontalScrollList.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding FieldVisualData}" 
                                    Margin="5">
                            <!--<Image.GestureRecognizers>
                                    <TapGestureRecognizer
                                        Command="{Binding HandlePreviewTapped, Source={x:Reference vm}}"
                                        CommandParameter="{Binding}"/>
                                </Image.GestureRecognizers>-->
                        </Image>
                    </DataTemplate>
                </controls:HorizontalScrollList.ItemTemplate>
            </controls:HorizontalScrollList>
        </StackLayout>

        <StackLayout  VerticalOptions="Start" BackgroundColor="White" Spacing="10">
            <!--DocumentData-->
            <Label Grid.Row="0" HorizontalOptions="CenterAndExpand" Text="Občanský průkaz" VerticalOptions="End" ></Label>
            <StackLayout BackgroundColor="Green"  VerticalOptions="FillAndExpand">
                <ListView x:Name="list" BackgroundColor="Red"
                    HasUnevenRows="True"
                    HorizontalOptions="CenterAndExpand"
                    VerticalOptions="CenterAndExpand"
                    VerticalScrollBarVisibility="Never"
                    CachingStrategy="RecycleElement"
                   ItemsSource="{Binding Results, Mode=TwoWay}"
                    SeparatorVisibility="Default"
                    SelectionMode="None">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Grid  BackgroundColor="Beige" Padding="10" >
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="15*"/>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="12*"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Grid.Column="1" Padding="0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" BackgroundColor="Gray" HorizontalTextAlignment="Start"/>
                                    <Label Grid.Column="3" Padding="0" Text="{Binding FieldValue}" FontSize="Small" TextColor="#6781a3"  BackgroundColor="AliceBlue" HorizontalOptions="Start" HorizontalTextAlignment="Start">
                                        <Label.GestureRecognizers>
                                            <TapGestureRecognizer
                                                Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}"  
                                                CommandParameter="{Binding .}"
                                                
                                                
                                                />
                                        </Label.GestureRecognizers>
                                    </Label>
                                </Grid>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>
        </StackLayout>
    </StackLayout>

Here is layout background code.

   public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            IEnumerable<DocumentData> data = new DocumentData[] { new DocumentData() { FieldDescriptor="test 1", FieldValue=1, FieldVisualData= "https://aka.ms/campus.jpg" } };
            data = data.Append(new DocumentData() { FieldDescriptor = "test 2", FieldValue = 2, FieldVisualData = "https://aka.ms/campus.jpg" });
            data = data.Append(new DocumentData() { FieldDescriptor = "test 3", FieldValue = 3, FieldVisualData = "https://aka.ms/campus.jpg" });

            this.BindingContext = new ResultPageViewModel(data);
        }
    }