Reputation: 51
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;
}
Upvotes: 1
Views: 883
Reputation: 9234
Do you want to acheve the result like following GIF?
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 ResultPageViewModel
s 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.
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);
}
}
Upvotes: 0