How to user a simple list with a collection view - c#

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

Related

Communicate between TabbedPages in Xamarin

I have a question. I created a TabbedPage with 2 childs. In child1 I want to show the selected images. In child2 I have a Grid with a few images. Now I want to make the images in child2 selectable and when they get clicked, I want them to be inserted in the StackLayout in child1. I have no clue how to start, so can someone give me an example?
Here is the xaml from child1:
<ContentPage.Content>
<StackLayout BackgroundColor="White" x:Name="MainLayout" VerticalOptions="Center">
</StackLayout>
</ContentPage.Content>
Here is the Grid from child2
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Image Grid.Row="1" Grid.Column="1" Source="Good_Question.png" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" />
<Image Grid.Row="1" Grid.Column="3" Source="Excuse_Me.png" />
</Grid>
Can someone give me an example of how I can add an Image that is selected in a different tab to another tab in a TabbedPage?
There are multiple ways to do so:
1 way(Simple):
Create a public static ObservableCollection<Image> imageCollection= new ObservableCollection<Image>(); on main page.
Then On Page2 : Add the selected images inside imageCollection .
On Page1: Add imageCollection.CollectionChanged += AddImageInsdeFirstPageLayout();.
CollectionChanged is call whenever any element is added/removed inside ObservableCollection.
2nd way(Work throuh MVVM logic & Preferred way):
Create a common ViewModel for all three pages(main Page & tabbed Pages).
Create a property inside it,namely,
public ObservableCollection<Image> _selectedImages { get; set; }
public ObservableCollection<Image> SelectedImages
{
get { return _selectedImages; }
set
{
_selectedImages = value;
OnPropertyChanged();
}
}
Add new elements inside this property from Page2 and access this property from Page1.
Make sure, you raise OnPropertyChanged
3rd way(i don't like this):
Use MessagingCenter. It's pretty simple to use.Go through this,if you want to dig more: Xamarin.Forms MessageCnter
My suggestion is use a tabbed view instead of tabbed pages https://help.syncfusion.com/xamarin/tabbed-view/getting-started .
Use Two ListViews in both Child Tabs, and when the Second Child tab's image is selected, get the selected item from ItemSelectedEvent and bind it to the First Child tab's listview. And if you need, you can removed the selected item from Second Tab's ListView.
AS both listviews in same page you dont have to worry about passing data between pages.
you can use a MessageCenter to translate the Image Source.
google the Xamarin api to add it then all will be ok.

How to add 2 rows of different images using collection view in xamarin forms

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.

Label in ListView not binding on Collection Clear

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.

Cannot cast object of type ContentPage to type ContentPage

So I am currently working on my first Xamarin application.
I have a MasterDetailPage with a menu, and when you click on one of the menu items on the left the below I save the object I am working with (to the file system), I create a new 'ContentPage' for the page they have chosen and pass in the object as a constructor parameter.
I then attempt to set the MasterDetailPage Detail object to (ContentPage)obj which is a cast of the content page they have chosen.
Now as you can see, the base for the JobDetails is a ContentPage, yet I cannot cast it to content page!?
I have also tried casting to Page instead to no avail.
Am I missing some fundamental knowledge when it comes to casting, or is something else going on here?
I have solved this.
The issue wasn't with the Content Page cast (casting from obj > content page) but was because I had some xaml which wasn't correct inside JobDetails page.
The offending xaml was a
<ListView Grid.Row="3" Grid.ColumnSpan="2" Grid.Column="0" x:Name="KeySkillsList">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Name, Mode=TwoWay}"></Label>
<Switch Grid.Row="0" Grid.Column="1" IsToggled="{Binding Value, Mode=TwoWay}"></Switch>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This was due to me misunderstanding the list view (and the switch!)
The actual offending line specifically was the , commented out the page works.
I have now changed this so that its just a normal list view, with 1 switchcell, with a Text property.

WPF DataGrid Gives ArgumentOutOfRangeException when clicked

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>

Categories

Resources