I have a list view set with item source as child. I want to bind a child object to a view which will set the color through the converter.
The converter method got called but the value i passed in was null.
Apart from dot, I also use Path=/ but the value passed to the converter still null. If i bind the property, it's fine but not the current item.
<ListView x:Name="childListView"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
ItemSelected="OnItemSelected"
ItemTapped="OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout
BackgroundColor="{Binding ., Converter={StaticResource accountedToColorConverter}}"
Spacing="0" Padding="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" Spacing="10" Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="StartAndExpand">
<controls:CircleImage>
This is an interesting bit of behavior. I recently had this while working with CarouselView (Forms.Plugin), and doing more research, it turned out that the BindingContext of each of CarouselView element is set more than once for some reason.
So the first time, the converter gets null value, but eventually, it gets called a second time with the correct value, so I changed my converter to gracefully handle null values, and it worked.
Phatye is definitely correct in saying the line
BackgroundColor="{Binding ., Converter={StaticResource accountedToColorConverter}}"
is the culprit. I too have attempted to use the {Binding .} and {Binding Path=.} with a converter in the past only to run into the same null reference issues you're running into. It seems that Xamarin doesn't like this.
The proper solution will be to pass the proper path of the property you want to bind to:
Assuming the property is a top level property
BackgroundColor="{Binding Path=accounted, Converter={StaticResource accountedToColorConverter}}"
Otherwise you could do this:
BackgroundColor="{Binding Path=topLevelProperty.accounted, Converter={StaticResource accountedToColorConverter}}"
BackgroundColor="{Binding ., Converter={StaticResource accountedToColorConverter}}"
That line is the likely culprit. It will only be valid if the binding context of the page is that single "AccountedTo" property. Change it to "{Binding BackgroundProperty}"
where "BackgroundProperty" is the "AccountedTo" value.
Related
We have a ListView bound to a List of objects of a type called Trial. Each Trial has a property, called Pictures, that is a List of objects of a type, Picture, that represents an image and some metadata. We are using a horizontal CollectionView within the ListView item template to display thumbnails of the images, if any. The problem is in getting a little space between the images. We've tried setting a Margin property value on the Image in the CollectionView item template, but the images are still appearing right next to each other as seen in the illustration.
This is the XAML describing the ListView:
<ListView x:Name="trialsListView"
ItemsSource="{Binding .}"
ItemTapped="Handle_ItemTapped"
CachingStrategy="RecycleElement"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="20">
<Label
Text="{Binding Prompt}"
BackgroundColor="{Binding TrialType, Converter={StaticResource TrialTypeToColorConverter}}"
Padding="5" />
<Label Text="{Binding Response}" />
<CollectionView
BindingContext="{Binding Pictures}"
ItemsSource="{Binding .}"
ItemsLayout="HorizontalList"
HeightRequest="{Binding Count, Converter={StaticResource PicturesCountToHeightConverter}}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Image
HeightRequest="80"
Source="{Binding PictureName, Converter={StaticResource PictureNameToImageSourceConverter}}"
Margin="10" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is an example of output (from an iOS device):
I suppose we can enclose the Image in a Frame or some layout, but that feels like a 90s web hack. Surely there is a right way to get some spacing without resorting to adding screen elements? What do I not yet understand here?
I have a list view which I am using to display a form.
Here is my item source:
ObservableCollection<ContactBlockFieldViewModel> ContactBlockFIelds
Each ContactBlockFieldViewModel contains public EContactFieldTypeDTO ContactField { get; set; }
I want to bind the listview entry behavior property to specific behavior, depending on what type of contact field it is.
For example, for email type I would want my custom EmailValidationBehavior.
How can I accomplish this? I tried putting the behavior right in the viewmodel and then
<ListView ItemsSource="{Binding ContactBlockFields}" x:Name="ContactFieldsList">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding FormDisplayName}" HorizontalTextAlignment="Start"></Label>
<Entry Text="{Binding Value}" BackgroundColor="{Binding BackgroundColor}">
<Entry.Behaviors>
<Binding Path="BehaviorInViewModel"></Binding>
</Entry.Behaviors>
</Entry>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
But it didn't work, I also tried to use a converter which would convert the enum to Behavior but also without success. I checked in debug and the constructor of the behavior gets called, but the object is not being bound.
I can't get databinding to work within a DataTemplate in Xamarin forms. I can get it to work with the ListView (i.e. binding the RowHeight), but once in the DataTemplate, setting things to a property of my ViewModel has no affect.
In the below example, if I set the ColumnDefinition.Width to a property, it is completely ignored, but setting it to a hard value works fine. I have put in a label to see what the property value is and it turns out blank when inside the Datatemplate, and I have re-checked that the property is correct because if I take the label out of the Listview, it displays the correct value.
Any ideas?
UPDATE:
My Class is "ParentPage" which has 2 properties: "Patients" and "Settings". Patients has an observable collection of "PatientList", How would I bind to the "Settings.Fontsize" shown below in the label. I have tried every combination I can think of:
<ListView x:Name="listView" ItemsSource="{Binding ParentPage.Patients.PatientsList}" RowHeight="{Binding ParentPage.Settings.RowHeight}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Grid.Column="0"
Source="{Binding Picture}" />
<Label TextColor="Red" Text="{Binding ParentPage.Settings.FontSize}"
HorizontalOptions="Center" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
BindingContext, in other words "ItemsSource" for listview, is appliying to whole listview, include DataTemplate. So, if you wanna bind something, then it property should be in BindingContext, in your case it is Patients. So, Pasient class should include this property. But, there is a trick. Where you want bind something, that is not in listview binding context, then you should name your listview, like x:Name = "YourListView" and then in your datatemplate for your binding write this:
Property="{Binding Source={x:Reference Name = "YourListView"},
Path=BindingContext.YourNameOfPropertyInViewModel}"
With this, your property will use binding context of your listview element level, that is ViewModel in your case.
I am using the following XAML code to render some data in a ListView:
<ListView x:Name="myListView"
ItemsSource="{Binding myData}"
RowHeight="230">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<RelativeLayout Padding="1">
<StackLayout x:Name="stackLayoutTitle"
Padding="5"
Orientation="Vertical"
VerticalOptions="EndAndExpand"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.6}">
<Label Text="{Binding myText}"
FontSize="Medium"
FontAttributes="Bold"
TextColor="Black">
</Label>
</StackLayout>
</RelativeLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The data is rendering OK. Now, what I would like to do is to use banding for the Factor property of the RelativeYConstranit to position the respective StackLayout based on some calculation. Something like this (see the Factor property):
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor={Binding someValue}}"
But, when running the App I am getting an error.
Does anyone knows if it's possible to using binding expression for this?
Thanks.
I have this problem. "Factor" is not BindingProperty. Therefore now is not possible.
I tried a similar thing and failed to bind factor for YConstraint, here is an explanation of why it doesn't work
From the documentation:
In C#, relative constraints are defined as functions. Concepts like Factor aren't there, but can be implemented manually.
The error message I got:
Cannot assig property "Factor": Property does not exist, or is not assignable, or mismatching type between value and property
Conclusion:
There is no bindable property (note it has to be a bindable property otherwise you can not bind) Factor in the underlying code so it is not possible to bind.
I have a ListView whose ItemSource is binded to ArticleList. I need to Bind the FontSize of the Label inside it to MyFontSize which is NOT inside ArticleList. Its just another property in my view model, just like ArticleList
XAML code:
<ListView ItemsSource="{Binding ArticleList}"
x:Name="ArticleListView" HasUnevenRows="True"
SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<ContentView>
<StackLayout Padding="10,0,20,10">
<Image Source="{Binding _Image}"/>
<Label Text="{Binding _Description}"
FontSize="{Binding MyFontSize}"/>
</StackLayout>
</ContentView>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You need to 'target' the element which holds the correct datacontext for your ViewModel. I would guess you hooked it up to your page? Anyhow, the syntax is as follows - with elementname the element with the correct datacontext.
{Binding DataContext.MyFontSize, ElementName=LayoutRoot}
Great catch by Dushyant Bangal, seems in Xamarin you need to use the Source property for the binding to work :)
FontSize="{Binding BindingContext.MyFontSize, Source={Reference LayoutRoot}}"
Try something like this:
FontSize="{Binding ElementName=ArticleListView, Path=DataContext.MyFontSize}"