I have a Xamarin form with a listview. In the view cell I have a label and an Entry which are bound to 2 properties on an object in an observable collection.
When I first load the form and add to the collection this works fine. Then I call Collection Clear(). Then I add a new item to the collection and the Entry shows but the Label does not. But if I change the label to an Entry then it works.
Also, if I add a second item to the collection the label on the second and successive items also display. It is just the first one after calling Clear().
Am I missing something special for a label?
This is the data template in the xaml form
<DataTemplate>
<ViewCell>
<Grid HeightRequest="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding UpcName}" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center"/>
<Entry Keyboard="Numeric"
Text="{Binding Quantity}"
Grid.Column="1"
HorizontalTextAlignment="Center"
WidthRequest="40"
VerticalOptions="Center"
HorizontalOptions="Center"/>
<customControls:ExtendedButton Text="DEL"
Command="{Binding Path=BindingContext.DeleteInventoryCommand, Source={x:Reference UpcListView}}"
CommandParameter="{Binding .}"
Style="{StaticResource SmallDestrutiveButtonStyle}"
Grid.Column="2"
FontSize="12"
VerticalOptions="Center"
HorizontalOptions="Center"/>
</Grid>
</ViewCell>
</DataTemplate>
and this is the property it is bound to
var inventory = new InventoryItemVM
{
Id = upcDetail.Id,
Upc = upcDetail.UPC,
UpcName = upcDetail.Name,
Quantity = 1,
BrandImage = upcDetail.BottleImage
};
Inventories.Add(inventory);
later I call
Inventories.Clear();
Then next time I add the inventory the label does not show the UpcName. But add a second one and it does for that one. Or change the label for an Entry and it works every time.
Any ideas please?
UPDATE AND FIX:
If anyone else has this issue, it is to do with the label sizing (or more specifically NOT resizing on content change).
When I removed an item or cleared the list the label bound to a null value and set it's width to 0. Then when the content changed, it did not resize (I dont see a way to get it to resize - so if someone knows, please let me know).
The way around this was to set the FallbackValue on the label (e.g. Uknown) and set the labels HorizontalOptions to fill. Then it worked.
So it was always binding correctly but not rendering correctly.
It's probably debause of the mode of the binding :
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/binding-mode
Entry have a two way mode by default, and label does not, so you can't change it's content from the Viewmodel without specifying that you will.
you should try with
<Label Text={Binding Upcname, Mode=TwoWay}/>
I hope this helps.
Related
I have a List object called mylist that contains a list of strings that represent names stored in a database. I want to display this list in a collection view. So far, i've been able to set the collection view itemsource property to mylist, which works fine. when i do this, it shows me the list in the default mode for collection view which is a vertical list. Now, i want to actually apply some formatting to the list by putting it inside of a grid and making it look nice. This is where my issue is. All of the examples on microsoft documentation set the Binding of the collection view to some class, and then they set the binding for the views in the list to the properties of that class. The issue with that for me is that I am not using the MVVM architecture. I am not setting the binding to a class. I want to set it directly to a list object. This is what i have so far for my xaml
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0"
Grid.Column="0"
Text=**WHAT DO I PUT HERE**
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="0"
Text=**WHAT DO I PUT HERE**
/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
...
</CollectionView>
and from my code behind file here is the relevant snippet
```Collection.Itemsource = mylist;
```
As you can see, i want to display the data that is in my list string in the text of the labels i have created. but i don't know how to reference that data. I've already tried mylist[0] but that doesn't work
if your ItemSource is a List<string>
Text=**WHAT DO I PUT HERE**
should be
Text="{Binding .}"
. tells it to use the value of the object itself, not a property of the object
View Image here..See section circled with black ink l want to add a second row to the Collection view in my project. This second row is suppose to be horizontal list the first one and consist of different images
l have tried adding another image tag to the collection view template but it does solve my problem as it repeats the same images twice. Find my code below
<CollectionView ItemsSource="{Binding sliders}"
HorizontalOptions="CenterAndExpand" HeightRequest="150" >
<CollectionView.ItemsLayout>
<ListItemsLayout>
<x:Arguments>
<ItemsLayoutOrientation>Horizontal</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid BackgroundColor="#282626" Padding="0,5,0,0" >
<Grid.RowDefinitions >
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Url}"
Aspect="AspectFill"
HeightRequest="160"
WidthRequest="160"
Grid.Row="0"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"/>
<Label Text="{Binding Name}" TextColor="White" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
The code above adds a collections view with one row to the project.
Kindly help me add a second row with different images.
The CollectionView element displays one row per object in your Source (in this case, "sliders"). So, in order to create another row, you have to simply add another object to your "sliders" list with the image you want to be displayed in the second row.
Adding another Image to the DataTemplate will not work because it will be referencing the same object, and if you're using the same property as the image source (in this case, "Url"), it will display the same image.
I am fairly new to WPF and MVVM and a newb in general, so thank you in advance for your patience.
I am using a custom class in my model, and I have an ObservableCollection of that custom object in my viewmodel. In the class' constructor, I am adding the object to the collection when it is instantiated. In my view, I am using a DataGrid that is bound to the collection to list all active instances of the class. I am trying to implement a drag-and-drop from the DataGrid onto a trash can icon that would allow a user to dispose of unneeded instances of the class.
The problem is that when you click anything in the DataGrid, the program immediately crashes with an ArgumentOutOfRange exception - ("The given DisplayIndex is out of range. DisplayIndex must be greater than or equal to 0 and less than Columns.Count." "Actual value was 0"). DisplayIndex seems to relate to the DataGrid column, so this exception is probably due to the fact that I am not displaying any columns in the traditional sense - in my DataGrid, AutoGenerateColumns is set to False, and I am displaying everything I need to display using a RowDetailsTemplate. (The reason for this is that the area where I am displaying the DataGrid is narrow, so I need a nested, item-specific grid to represent the item properly.) The DataGrid displays and syncs with the collection fine, but obviously has some issues. I have read dozens of links on DataGrid crashes, and haven't found anything involving this exception.
My desired behavior is to pass the custom object represented by the DataGrid item to a target when I drag and drop it. I don't care which "column" they clicked or anything else - I just need a way to pass either an object reference or a SelectedIndex (the items index in the collection) to a method in the viewmodel.
Thank you in advance for any help! The offending bit of code (XAML) seems to be:
<ScrollViewer DockPanel.Dock="Bottom" Margin="2" Width="180" ScrollViewer.VerticalScrollBarVisibility="Auto">
<DataGrid ItemsSource="{Binding Path=myCollection, Mode=OneWay}" AutoGenerateColumns="False" RowDetailsVisibilityMode="Visible" HeadersVisibility="None">
<DataGrid.RowDetailsTemplate>
<DataTemplate DataType="model:myClass">
<Border CornerRadius="10" Background="AliceBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding MyString1}" FontSize="21" VerticalAlignment="Bottom" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding MyCustomProperty, Converter={StaticResource MyIValueConverter}}" VerticalAlignment="Bottom" />
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding MyString2}" TextWrapping="Wrap" />
<Image Source="/Resources/image1.png" Grid.Column="2" Grid.Row="0">
<Image.DataContext>
<Properties:Resources/>
</Image.DataContext>
</Image>
<Image Source="/Resources/image2.png" Grid.Column="2" Grid.Row="1">
<Image.DataContext>
<Properties:Resources/>
</Image.DataContext>
</Image>
</Grid>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</ScrollViewer>
The issue was indeed because I am not generating any "traditional" columns. This is apparently a known bug, documented here: Microsoft Bug Report
As a workaround, I just defined an invisible column within the DataGrid and it seems to behave properly now:
<DataGrid.Columns>
<DataGridTemplateColumn Visibility="Hidden" />
</DataGrid.Columns>
I have a Grid inside a ListBox bound to a list of items. When I press a global 'edit' button, I want a series of checkboxes to appear in the Grid. I was planning on doing this in a similar fashion to how orientation change is handled, however I can't figure out how to access the bound grid to change the column properties
Here's my XAML:
<ListBox ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<CheckBox
Grid.Column="0"
Grid.ColumnSpan="1"
IsChecked="{Binding IsSelected, Mode=TwoWay}">
</CheckBox>
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="3"
Text="{Binding ItemName}">
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I was going to set the CheckBox and TextBlock ColumnSpan to 2 on edit mode, then back to 1/3 on cancel. But I can't access those.
Is there a smarter way to do this?
I also considered setting visibility on the Checkbox to a bound value, but this will mean the grid will still have a gap when not in edit mode.
I have a page that has a listbox with the following item template as follows:
<ListBox x:Name="test">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid MaxHeight="108" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Height="108" Grid.Column="0" Fill="{Binding Color}"/>
<Image Source="{Binding Image}" Height="108" Width="108" Grid.Column="1" HorizontalAlignment="Left" Stretch="UniformToFill"/>
<StackPanel Grid.Column="2">
<TextBlock Text="{Binding Title}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding SubHeading}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding Body}" TextWrapping="Wrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On the OnNavigatedTo event of the page, I set the item source of the list box to an observable collection of about 20 items.
All is well and the list is populated, however when I scroll up or down the list, the items appear to look out of sync on the UI. e.g the text that was shown on the first list item appears on the last item in the list box, sometimes there's duplicates, and everytime you swipe up or down the items are different.
I have debugged the listbox items, and I can see that correct objects are being bound to the right items. So it's only what is shown on the UI that is incorrect.
I have also tried explicitly using the standard stackpanel as opposed to a virtualizationstackpanel and that works around the issue by making sure all items are loaded in memory.
I don't believe that removing virtualization is the answer. There must be a root cause. However it may be acceptable as my listbox will never really contain more than 30 items.
On another page, I do the same thing with the silverlight toolkit longlistselector, and have the same issue. However I am not sure of how to remove virtualization on a longlistselector.
So to summarize, what might be the underlying issue that causes the listbox items to not update the UI properly when scrolling? If removing virtualization is the only answer, how may I do this on the longlistselector?
Thanks for anyhelp on this.
Maybe it is some sort this problem? (jumpy ListBox while scrolling)
As it turns out, it was a binding issue, and nothing to to with the listbox whatsoever.
I was (unknowingly) removing the binding of some properties in the item template, after I had bound to them (in some other bit of code) Therefore every time the listbox recycled the containers for new items, it could not update it with the correct info.
Thanks all for your help