Read the text of an Editor inside the DataTemplate - c#

I have a CollectionView with an Editor inside the DataTemplate. Through a button I would like to be able to read the text inside. How can I do?
<CollectionView
x:Name="CollectionEditIcon"
Grid.Row="0"
Grid.ColumnSpan="2"
Margin="10"
HorizontalOptions="Center"
SelectionMode="None">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1" VerticalItemSpacing="5" HorizontalItemSpacing="5"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="5"/>
<RowDefinition Height="27"/>
</Grid.RowDefinitions>
<Editor x:Name="EditName" Grid.Column="1" Grid.Row="1" Text="{Binding id}" TextColor="Gray" FontSize="16" MaxLength="40" IsReadOnly="True" IsVisible="{Binding Edit}"/>
<ImageButton Grid.Column="2" Grid.Row="1" BackgroundColor="Transparent" Source="IconEdit.png" Clicked="Edit_Clicked" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
With a button I can make the Editor visible, but then I can't go on
private void Edit_Clicked(object sender, EventArgs e)
{
var button = sender as ImageButton;
var model = button.BindingContext as IconDiary;
model.Edit = true;
}

your Editor is bound to the id property of the model. That means whatever the user enters in the Editor should be reflected in the model automatically
<Editor x:Name="EditName" Grid.Column="1" Grid.Row="1" Text="{Binding id}" TextColor="Gray" FontSize="16" MaxLength="40" IsReadOnly="True" IsVisible="{Binding Edit}"/>
private void Edit_Clicked(object sender, EventArgs e)
{
var button = sender as ImageButton;
var model = button.BindingContext as IconDiary;
model.Edit = true;
// the id property should contain the text the user entered
var text = model.id;
}

Related

Collect the identifier of a Button in a row of a CollectionView in xamarin forms

I am developing an application in xamarin forms and I have problems accessing the event of a button that I have in a CollectionView. For each button that is selected, depending on the row it is in, it will do a different thing with the id.
My xaml code with the CollectionView is as follows:
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="250" />
<ColumnDefinition Width="85" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="70" />
</Grid.ColumnDefinitions>
<Label Grid.Column="1"
Text="{Binding id_cliente}"
TextColor="black"
VerticalOptions="CenterAndExpand"
FontAttributes="Bold" />
<Label
Grid.Column="2"
Text="{Binding categoria}"
FontAttributes="Italic"
VerticalOptions="CenterAndExpand"
TextColor="black"/>
<Label Grid.Column="3"
Text="{Binding descripcion}"
TextColor="black"
VerticalOptions="CenterAndExpand"
FontAttributes="Bold" />
<Label
Grid.Column="4"
Text="{Binding estado}"
TextColor="Yellow"
VerticalOptions="CenterAndExpand"
FontAttributes="Bold" />
<Button Grid.Column="5" Text="Confirmar" BorderColor="#2b3c3c" BorderWidth="1" FontAttributes="Bold" BackgroundColor="#4ba862" TextColor="White" HeightRequest="60" Margin="0,0,0,0" x:Name="btnconfirmar" Clicked="ButtonConfirmacion_Clicked" Command="{Binding id_trabajo}"/>
<Button Grid.Column="6" Text="Asignar" BorderColor="#2b3c3c" BorderWidth="1" FontAttributes="Bold" BackgroundColor="#4ba862" TextColor="White" HeightRequest="60" Margin="0,0,0,0" x:Name="btnasignar" Clicked="ButtonListaTrabajos_Clicked"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And in the cs code of that page I have:
private void ButtonConfirmacion_Clicked(object sender, EventArgs e)
{
Trabajo selectedItem1 = e.CurrentSelection[0] as Trabajo;
}
This code, when that row is selected, with an OnSelectionChanged (sender, e) method if it picks up the item which has been selected.
You could use the code below to get the x:Name of button in a row.
private void ButtonConfirmacion_Clicked(object sender, EventArgs e)
{
var button = sender as Button;
var elemets = (button.Parent as Grid).Children;
foreach (var item in elemets)
{
if (item.GetType().Name == "Button")
{
var btn_name = item.StyleId;
}
}
}

CollectionView within a DataTemplate always remains empty

I have a CarouselView in which inside the DataTemplate I have a CollectionView, whose ItemsSource property is binded to an Observablecollection, in which elements are added only when the user presses on a button. The problem is that this CollectionView is always empty, I can't see any items
<CarouselView
x:Name="CollectionDiary"
RelativeLayout.YConstraint="{ConstraintExpression
Type=Constant,
Constant=242}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=1}"
PeekAreaInsets="20"
HeightRequest="330">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" SnapPointsType="MandatorySingle" SnapPointsAlignment="Center" ItemSpacing="5"/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<yummy:PancakeView CornerRadius="22" BackgroundColor="Transparent">
<yummy:PancakeView.Shadow>
<yummy:DropShadow Color="#000000" Offset="2,2" BlurRadius="5" Opacity="0.8" />
</yummy:PancakeView.Shadow>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="15"/>
<RowDefinition Height="45"/>
<RowDefinition Height="268"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Background>
<LinearGradientBrush StartPoint="1,0" EndPoint="1,1">
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="#4191cc" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Data}" FontSize="14" TextColor="Gray" VerticalTextAlignment="End" Margin="10,5,10,0"/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding Orario}" FontSize="14" TextColor="Gray" VerticalTextAlignment="End" Margin="10,0"/>
<Image Grid.Row="0" Grid.RowSpan="3" Grid.Column="0" Margin="15,15,0,0" Source="{Binding Umore}" HeightRequest="60"/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding TipoUmore}" FontAttributes="Bold" TextColor="{Binding ColoreUmore}" FontSize="22" Margin="10,0" VerticalOptions="Start"/>
<Label Grid.Row="3" Grid.Column="1" TextColor="White" FontSize="16" Text="{Binding Nota}" Margin="10,0" VerticalOptions="Start" HorizontalTextAlignment="Start"/>
<CollectionView
Grid.Row="2"
Grid.Column="0"
Margin="10"
SelectionMode="None"
ItemsSource="{Binding listEmojiDiarioView}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" VerticalItemSpacing="10" HorizontalItemSpacing="10"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Source="{Binding SourceImg}"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding id}" TextColor="White" FontSize="13"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</yummy:PancakeView>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
c#
ObservableCollection<HumorDiary> listDiario = new ObservableCollection<HumorDiary>();
ObservableCollection<IconDiary> listEmojiDiarioView = new ObservableCollection<IconDiary>();
private async void BTSaveDiary_Clicked(object sender, EventArgs e)
{
HumorDiary hum = new HumorDiary
{
Nota = TestoDiary.Text,
Data = DateTime.Today.Day.ToString() + " " + Mese,
Orario = DateTime.Now.TimeOfDay.ToString().Remove(5,DateTime.Now.TimeOfDay.ToString().Length-5),
Anno = DateTime.Now.Year.ToString(),
Umore = "Smile" + NUmore + ".png",
TipoUmore = tipoUmore,
ColoreUmore = Colore,
IconTot = NIcon,
};
string[] srListIcon = NIcon.Split(new string[] { set.Tag }, StringSplitOptions.RemoveEmptyEntries);
foreach (string sr in srListIcon)
{
string src = sr.Substring(0, 9);
string id = sr.Substring(9, sr.Length-9);
IconDiary ic = new IconDiary
{
SourceImg = src,
id = id,
};
listEmojiDiarioView.Add(ic);
}
listDiario.Insert(0, hum);
CollectionDiary.ItemsSource = listDiario.Take(3);
}
Since the BindingContext inside a CarouselView changes and takes it ItemsSource as a BindingContext, you need to explicitly specify your BindingContext in case of your CollectionView. I guess if you look at the logs you will find some binding error/failure because it was looking for an IEnumerable property with the name of listEmojiDiarioView inside listDiario which obviously is not there.
One way you can overcome this is by using a reference of your page as binding source:
<ContentPage x:Name="pageref" ...
<CollectionView ...
ItemsSource="{Binding Source={x:Reference pageref}, Path=BindingContext.listEmojiDiarioView}">
listEmojiDiarioView must be a property not a field
If it is not working check weather you have implemented the INotifyPropertyChanged on your ObservableCollection used in binding or no.
Omitted code remains unchanged.
Related documentation
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-binding-basics

How to set Listview Itemtemplate when drag drop in wpf

I have create simple drag drop in WPF. In my application there are two Listviews. I have to drag list items from first listview and drop the item to second listview. I have created custom data template for first listview. When i drag the first listview item into second listview the data template is not customized so items are not displayed. How to display the list items with generic. Please help. My Code is as below,
<Grid Margin="0,20,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListBox
Name="memberCollection"
Grid.Column="1"
Width="150"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
PreviewMouseLeftButtonDown="memberCollection_PreviewMouseLeftButtonDown">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid
Name="gridDrop"
Grid.Column="0"
Margin="20,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ListBox.Drop="grid_Drop"
ShowGridLines="True">
<ListBox
Grid.Row="0"
Grid.Column="0"
Margin="10,10,0,0"
AllowDrop="True" />
</Grid>
</Grid>
Code Behind
ObservableCollection<Member> member = new ObservableCollection<Member>();
public MainWindow()
{
InitializeComponent();
member.Add(new Member { Name = "Karthick", ID = "20011", Address = "10, MainRoad, Chennai" });
memberCollection.ItemsSource = member;
DataContext = new Member();
}
private void memberCollection_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
object selectedMember = memberCollection.SelectedItem as Member;
if (selectedMember != null)
DragDrop.DoDragDrop(memberCollection, selectedMember, DragDropEffects.All);
}
private void grid_Drop(object sender, RoutedEventArgs e)
{
ListBox listContent = e.Source as ListBox;
if (listContent != null)
Console.WriteLine("", Grid.GetColumn(listContent), Grid.GetRow(listContent));
DataObject item = (((DragEventArgs)e).Data) as DataObject;
object Target = ((Grid)(sender)).DataContext;
object listItem = item.GetData(Target.GetType());
if (listItem != null)
{
//listContent.Items.Add(listItem.Name.ToString());
//listContent.Items.Add(listItem.ID.ToString());
//listContent.Items.Add(listItem.Address.ToString());
//listContent.ItemTemplate = memberCollection.ItemTemplate;
listContent.Items.Add(listItem);
}
}
If you define the DataTemplate as a reusable resource, you can use it in both ListBoxes:
<Grid Margin="0,20,0,0">
<Grid.Resources>
<DataTemplate x:Key="dataTemplate">
<StackPanel>
<TextBox Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListBox
Name="memberCollection"
Grid.Column="1"
Width="150"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
PreviewMouseLeftButtonDown="memberCollection_PreviewMouseLeftButtonDown"
ItemTemplate="{StaticResource dataTemplate}" />
<Grid
Name="gridDrop"
Grid.Column="0"
Margin="20,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ListBox.Drop="grid_Drop"
ShowGridLines="True">
<ListBox
Grid.Row="0"
Grid.Column="0"
Margin="10,10,0,0"
AllowDrop="True"
ItemTemplate="{StaticResource dataTemplate}"/>
</Grid>
</Grid>
If you want to display some other properties of the dropped Member in the second ListBox, you should define another ItemTemplate:
<ListBox
Grid.Row="0"
Grid.Column="0"
Margin="10,10,0,0"
AllowDrop="True">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Id}" />
<TextBlock Tag="{Binding Address}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Get CommandParameter value from GestureRecognizers in Xamarin froms

I'm sending CommandParameter to TapGestureRecognizer, and it was available in object parameter of my OnTapGestureRecognizerTapped function. But I'm unable to extract value from it. How can I fix this?
My list view (XAML markup):
<ListView x:Name="listViewEvents" RowHeight="120" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="90"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" FontSize="Large" Grid.ColumnSpan="2" Text="{Binding UploadTitle}" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="0" Text="{Binding UploadDescription}" Font="Small" TextColor="Gray" LineBreakMode="TailTruncation"></Label>
<Image Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Source="{Binding AttachPath}" Aspect="AspectFill">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="2"
CommandParameter="{Binding AttachPath_New}"
/>
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding FileName}" LineBreakMode="TailTruncation"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My C# page :
void OnTapGestureRecognizerTapped(object sender, EventArgs args)
{
string fullPath = "";
Image imageSender = (Image)sender;
if (imageSender.GestureRecognizers.Count > 0)
{
fullPath = imageSender.GestureRecognizers[0].ToString();
}
DownloadFile(imageSender.Source.GetValue(UriImageSource.UriProperty).ToString());
}
Here I'm getting my value:
Another solution you can use is to typecast EventArgs to TappedEventArgs and expose the Parameter.
So to access the CommandParameter you would write the following:
private void OnTapped(object sender, EventArgs e)
{
var te = (TappedEventArgs)e;
string parameter = (string)te.Parameter;
....
You are trying to convert the entire GestureRecognizer to a string, not just its CommandParameter property.
void OnTapGestureRecognizerTapped(object sender, EventArgs args)
{
string fullPath = "";
Image imageSender = (Image)sender;
if (imageSender.GestureRecognizers.Count > 0)
{
var gesture = (TapGestureRecognizer)imageSender.GestureRecognizers[0];
fullPath = (string)gesture.CommandParameter;
}
DownloadFile(imageSender.Source.GetValue(UriImageSource.UriProperty).ToString());
}

Images disapearing in ListView when deleting an Item

I am currently working on a Xamarin CrossPlatform project and have implemented a Listview bound to an ObservableCollection. Everything works out fine until I remove an Item from the ListView. The images in the follow up items within the ListView disappear randomly - not all of them and a different amount of them every time. I guess it has something to do with the MemoryStream, but what do I have to change? Here´s the relevant part of my Model that is bound to the ListView:
public string ImageBase64
{
get
{
return imagebase64;
}
set
{
if (imagebase64 != value)
{
imagebase64 = value;
OnPropertyChanged(nameof(ImageBase64));
OnPropertyChanged(nameof(ImageSource));
}
}
}
public ImageSource ImageSource
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(Convert.FromBase64String(imagebase64)));
}
else
{
return null;
}
}
}
Here´s the relevant XAML:
<ListView x:Name="listView" Margin="20" ItemsSource="{Binding}" ItemSelected="OnListItemSelected" HasUnevenRows="True" SeparatorColor="{StaticResource primaryGreen}" SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.RowSpan="3" Margin="-2,-2,-2,-2" Source="{Binding ImageSource}" HorizontalOptions="Start" VerticalOptions="Center" Aspect="AspectFill"/> <!-- This is the displayed Image -->
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="0" FontAttributes="Bold" FontSize="18" TextColor="{StaticResource primaryGreen}" Text="{Binding VorNachname}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="1" Text="{Binding MediumSelected.Wert, StringFormat='via {0}'}" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<StackLayout Margin="10,0,0,0" Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Alter,StringFormat='Alter: {0}'}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start" HorizontalOptions="Start"/>
</StackLayout>
<StackLayout Margin="0,0,0,-5" Grid.Column="2" Grid.RowSpan="3" Orientation="Vertical" HorizontalOptions="End" VerticalOptions="End">
<Button WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderWidth="0" BorderColor="White" Image="socialmedia_18.png" Clicked="OnChangeClicked" CommandParameter ="{Binding}" VerticalOptions="EndAndExpand" />
<Button Margin="0,-15,0,0" WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderColor="White" Image="cancel_18.png" Clicked="OnDeleteClicked" CommandParameter ="{Binding}" VerticalOptions="End" />
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
...and the Code behind:
async void OnDeleteClicked(object sender, EventArgs e)
{
Helper.TrackEvent("PeopleList_OnDeleteClicked");
//Get selected Person
Person person = (Person)((Button)sender).CommandParameter;
//Remove from Model
DBHelper.DBModel.People.Remove(person);
//Update database
App.Database.UpdateWithChildren(DBHelper.DBModel);
}
EDIT:
Resizing the images does not help, same problem. I tried it by binding a testvariable ImageSourceThumb to the ListViewItemImage:
public ImageSource ImageSourceThumb
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(ImageResizer.ResizeImage(Convert.FromBase64String(imagebase64), 64, 64)));
}
else
{
return null;
}
}
}
I had a similar problem. When I loaded or updated my listview not all the images showed up.
I fixed my problem resizing the images. Huge images gived me a outofmemory exception. Resizing those images to a smaller resolution fixed these problems.

Categories