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.
Related
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 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.
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}"
I'm trying to select TreeViewItem on right mouse click. There is my XAML:
<TreeView x:Name="treeView" ItemsSource ="{Binding DisplayedDocuments}"
SelectedItemChanged="TreeView_SelectedItemChanged" IsEnabled="True"
MouseRightButtonDown="treeView_MouseRightButtonDown">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=DisplayedSubItems}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Converter={StaticResource docImageConverter}}"/>
<TextBlock Width="5"></TextBlock>
<TextBlock Text="{Binding Caption}"
MouseRightButtonDown="TextBlock_MouseRightButtonDown"/>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</TreeView>
When I click on treeViewItem sometimes TextBlock.MouseRightButtonDown raises instead of treeView.MouseRightButtonDown. So, I want to get treeViewItem by TextBlock in TextBlock_MouseRightButtonDown. I've tried to get it this way:
TextBlock docCaption = e.OriginalSource as TextBlock;
StackPanel stackPanel = docCaption.Parent as StackPanel;
But stackPanel.Parent is null.
I've tried to find the control by name:
TreeViewItem treeViewItem = (TreeViewItem)treeView.FindName(docCaption.Text);
but it returns null.
Use the VisualTreeHelper to get the parent: http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx
http://miguelmadero.blogspot.com.au/2008/07/use-visualtreehelper-to-navigate.html
I have the following item template in a WP7 listbox. My bound type has a boolean property (Status) and I would like to conditionally set the colour of the site name based on this. How would I go about doing this please?
Thanks in advance!
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding SiteName}" TextWrapping="Wrap" />
<TextBlock Text="{Binding Url}" TextWrapping="Wrap" Margin="12,-6,12,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
The easiest way to do this is with a converter. Either you can have the converter return a color, or you can have two TextBlocks each with the color you want, and use a Boolean to Visibility, and one that is a reverse visibility, converters to hide/show each of the controls.
One word of caution is that converters can be slow, so sometimes it's more performant to bind to a ViewModel and on that ViewModel provide the convetered values that you need.