xamarin listview get selected item - c#

Cannot figure out a proper way get an item from ListView.
My XAML bindings:
<ListView x:Name="MyListView" ItemTapped="MyListView_ItemTapped" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding Email}"></Label>
<Image Source="{Binding PhotoUrl}" WidthRequest="20" HeightRequest="20"></Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
All the data gets displayed and works fine. Class is called Forums:
[JsonProperty("results")]
public List<Result> Results { get; set; }
public class Result
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("photoUrl")]
public string PhotoUrl { get; set; }
}
I have made MyListView_ItemTapped Function and for now, I'm trying to display its name when the item is tapped on, but not sure what is a proper way to do it. And I always think that I'm just bodging some random things together until I get something.
private void MyListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var index = forums.Results.IndexOf(e.Item as Forums.Result);
DisplayAlert("Alert", forums.Results[index].Name, "OK");
}
So if anyone could point me to the better direction or even give few better examples or just explain how should it be done.

just cast e.Item to the correct type
var item = e.Item as Forums.Result;
// then use item.Name, etc...

You can also use selected item property
<ListView **SelectedItem="{Binding Result, Mode=TwoWay}">**
code behind:
`private Result _result;
public Result Result
{
get { return _deviceSession; }
set
{
SetProperty(ref _deviceSession, value);
}
}`
From this class object you can able to get all data

You can cast to the correct Class
private void MyListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var index = forums.Results.IndexOf(e.Item as Forums.Result);
var selectedItem = (Forums.Result)e.Item;
if(selectedItem != null)
{
DisplayAlert("Alert", selected|Item.Name, "OK");
}
}
Oh and if you want to remove the selecteditem effect just
if (sender is ListView lv) lv.SelectedItem = null;

Related

Can't insert data from Sqlite in ListView

I'm trying to insert certain pieces of data of a user into a ListView, but can't seem to get any of them to show up.
This is how my code looks like so far. The issue is in the last two classes (Invite_Page.xaml.cs and Invite_Page.xaml), but I also pasted my notes from other classes which could be relevant.:
User.cs:
public class User {
public string fName { get; set; }
public string lName { get; set; }
public string uName { get; set; }
public string Pw { get; set; }
// public string cls { get; set; }
}
fName and lName are both Strings
DatabaseManager.cs:
public class DatabaseManager
{
SQLiteConnection dbConnection;
public DatabaseManager()
{
dbConnection = DependencyService.Get<IDBInterface>().CreateConnection();
}
public List<User> GetAllUsers()
return dbConnection.Query<User>("Select * From [User]");
public int SaveUser(User aUser)
{
//dbConnection.CreateTable<User>();
//return 1;
return dbConnection.Insert(aUser);
}
public List<User> GetAllNames()
return dbConnection.Query<User>("Select fName, lName From [User] ORDER BY fName;");
//.....
Invite_Page.xaml:
<ListView
x:Name="invitees"
SeparatorColor="White"
BackgroundColor="Transparent"
ItemsSource="{Binding invitees}"
IsGroupingEnabled="true"
IsPullToRefreshEnabled="true"
ItemTapped="Handle_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding}" TextColor="White"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Invite_Page.xaml.cs:
DatabaseManager DBM = new DatabaseManager();
// List<User> Invitees(String SearchText = null)
// {
// invitees.ItemsSource = DBM.GetAllNames();
// return Invitees();
// }
protected override void OnAppearing()
{
base.OnAppearing();
invitees.ItemsSource = DBM.GetAllNames();
}
In the Invite_Page.xaml.cs code, you can see that I tried inputting the data by using the code that is commented out. The result of that was that nothing showed up in the list. But with the second method which isn't commented out, the result was that "RoseySports.User" was placed in the ListView. I'm trying to make it so that the values of fName and lName are put together as one string, and are placed in the ListView.
The easiest way is to override ToString() method of the User class:
public override string ToString()
{
return fName + " " + lName;
}
The other option is to build more complicated DataTemplate as #ViralThakker mentioned.
P.S. The line ItemsSource="{Binding invitees}" in your XAML is unusable if you are assigning ItemsSource in code.
First, you have to specify what you really want from the model of User to the TextCell that you use binding. You set as ItemSource Users, but you just set TextCell Binding without any variable. Try to set Text={Binding fName} for example.
Second, try to use ViewModel to populate data. Learn more here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/mvvm
You need to create Custom List item template to display value from your object.
For example you want to display fName,lName and uName then you'll have to use below code for binding values to list item
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="10">
<Label Text="{Binding fName}" TextColor="White"/>
<Label Text="{Binding lName}" TextColor="White"/>
<Label Text="{Binding uName}" TextColor="White"/>
</StackLayout>
</ViewCell>
</DataTemplate>

Control inside datatemplate in ListBox UWP xaml

I have a ListBox consist of Datatemplate.
Here is my code:
<ListBox x:Name="MyListBox" SelectionChanged="MyListBox_SelectionChanged_1" SelectionMode="Single" IsItemClickEnabled="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="50" Height="45" Name="myRectangle" Fill="DodgerBlue" />
<Ellipse Grid.Column="0" Fill="LightGreen" Height="22" Width="22" />
<TextBlock Text="{Binding Initials}" x:Name="PersonInitials" />
<stackpanel>
<TextBlock TextWrapping="Wrap" x:Name="person_lbl" Text="{Binding SourceLink}" Foreground="DodgerBlue"/>
<TextBlock TextWrapping="Wrap" x:Name="detail_lbl" Text="{Binding ConversationId}" Foreground="DarkSlateGray"/>
</StackPanel>
<ToggleSwitch OffContent=" "/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Datatemplate consist of rectangle,Ellipse,3 textblocks and toggle switch which finally give an output like this as shown in image.
This is the template I will get.Please ignore the search bar.
Now Here is my Query:
I want to perform action on the basis of selection of a data_template in the listBox in which it should fetch the text of the textbox and display it somewhere.After searching about it on internet I have only found the examples like
<listbox>item1</listbox>
My ListBox does not consist of only one item it has many items that is making a template.
How can I fetch one textbox element on selection of whole template.Does anyone has idea how do so?
This is my code in c#:
class ReadJsonData
{
public List<Information> information { get; set; }
public ReadJsonData()
{
information = new List<Information>();
}
}
public class Information
{
public string SourceLink { get; set; }
public int ConversationId { get; set; }
public string Initials { get; set; }
}
and this is on MainPage.xaml
public MainPage()
{
this.InitializeComponent();
JsonReader();
}
public async void JsonReader()
{
Information infos = new Information();
infos.ConversationId = 1122;
infos.Initials = "LM";
infos.SourceLink = "abc";
Information info1 = new Information();
info1.ConversationId = 111;
info1.Initials = "MM";
info1.SourceLink = "pqr";
Information info2 = new Information();
info2.ConversationId = 1113;
info2.Initials = "NM";
info2.SourceLink = "vrl";
ReadJsonData rb = new ReadJsonData();
rb.information.Add(infos);
rb.information.Add(info1);
rb.information.Add(info2);
var rb1 = JsonConvert.SerializeObject(rb);
var rootobject = JsonConvert.DeserializeObject<ReadJsonData>(rb1);
foreach (var info in rootobject.information)
{
MyListBox.ItemsSource = rootobject.information;
}
private void MyListBox_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
var selectedItem = sender as Information;
string initials = selectedItem.Initials;
show_initial = initials;
}
}
Assuming you are setting the item source of the ListBox (MyListBox) to a list of items of your model class (List<SomeClassName>)..
If your model class is something like this :
public class SomeClassName
{
public string Initials { get; set; }
public string SourceLink { get; set; }
public string ConversationId { get; set; }
}
You can add this code to the OnSelectionChanged or Tapped event of your listbox to get the data members of the class:
private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = sender as SomeClassName;
//Gives you the Initials of the selected list item
string intials = selectedItem.Initials;
}
Hope this helps..!
EDIT 1 :
First of all why are you iterating rootobject.information? you can simply use it as item source without the for loop..
foreach (var info in rootobject.information)
{
MyListBox.ItemsSource = rootobject.information;
}
Second, what does this line do ? show_initial = initials; is show_initial a variable ? what does it do ?
Edit 2 :
private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(MyListBox.SelectedItem != null)
{
var selectedItem = sender as Information;
//Gives you the Initials of the selected list item
string intials = selectedItem.Initials;
} else {
Debug.WriteLine("No item Selected");
}
}
Please check if the MyListBox.SelectedItem != null condition is satisfied or not.

Not able to make bindings in treeview

Im trying to make a custom treeview with an itemtemplate, so I can show the headertext + a type of the item in the treeview.
My inspiration comes from this answer;
https://stackoverflow.com/a/33119107/9156219
So, my problem is that I cant make the Itembindings work.
Here's my code;
XAML:
<TreeView x:Name="treeView" ItemsSource="{Binding treeList}" Grid.Column="0" IsVisibleChanged="treeView_IsVisibleChanged" SelectedItemChanged="treeView_SelectedItemChanged">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Type}" Margin="2,2,2,2" Background="LightBlue" FontSize='8'/>
<TextBlock Text="{Binding SystemName}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
C#
public class CustomTreeViewItem : TreeViewItem
{
public String SystemName { get; set; }
public String Type { get; set; }
public String ParentItem { get; set; }
public String Path { get; set; }
}
public List<CustomTreeViewItem> treeList = new List<CustomTreeViewItem>();
public void SetRootNode()
{
int itmNumber = datSet.Rows.Count;
for (int i = 0; i < itmNumber; i++)
{
treeList.Add(new CustomTreeViewItem
{
SystemName = (string)datSet.Rows[i].ItemArray[1].ToString(),
Type = (string)datSet.Rows[i].ItemArray[2].ToString(),
ParentItem = (string)datSet.Rows[i].ItemArray[3].ToString(),
Path = (string)datSet.Rows[i].ItemArray[4].ToString(),
});
treeList[i].Header = treeList[i].SystemName;
}
foreach (CustomTreeViewItem item in treeList.Where(treeList => treeList.ParentItem == ""))
{
treeView.Items.Add(item);
}
foreach (CustomTreeViewItem item in treeList.Where(treeList => treeList.ParentItem != "").Where(treeList => treeList.Type != "Signal"))
{
var test = treeList.Find(treeList => treeList.SystemName == item.ParentItem);
test.Items.Add(item);
}
}
SetRootNode() is being called in the beginning of the program. datSet is being filled with a OleDBDataAdapter.
In the treeview, only the SystemName is being showed and not the type. What am I doing wrong?
Thank you in advance!
You are trying to create a TreeView whose TreeViewItems contain yet again TreeViewItems, if you remove the inheritance for your model, it works:
do this:
public class CustomTreeViewItem
instead of
public class CustomTreeViewItem : TreeViewItem
is this good enough for your needs?

Data Binding to a list of objects within a List of objects within a list of objects in xaml

I have got myself in a bind. I'm trying to bind to a 3rd level list(basically the hierarchy is Food->Veges->Carrots). So my idea is that when you click a page of food, it brings up different subcategories of food, and for example if you select vegetables, it brings up different vegetables, and say for example you click carrot, it brings up different types of carrots based on your selection...and so on, I've been able to bind to the 2nd hierarchy(veges), but can't get to the third hierarchy based on selection. Your help would be appreciated..This is an idea of my classes:
public class Food: INotifyPropertyChanged
{
public string FoodName {get;set;}
private List<Vegetable> _veges = new List<Vegetable>();
public List<Vegetable> Veges
{
get
{
return _veges;
}
set
{
if (value != _veges)
{
_veges = value;
NotifyPropertyChanged("Veges");
}
}
}
}
Then the Vegetable class is like so:
public class Vegetable: INotifyPropertyChanged
{
public string VegeName {get;set;}
private List<Carrots> _carrot = new List<Carrots>();
public List<Carrots> Carrot
{
get
{
return _carrot;
}
set
{
if (value != _carrot)
{
_carrot = value;
NotifyPropertyChanged("Carrot");
}
}
}
}
The carrot class is similar:
Public class Carrot: INotifyPropertyChanged
{
public string CarrotTypeName {get;set;}
private List<CarrotType> _carrottype = new List<CarrotType>();
public List<CarrotType> CarrotT
{
get
{
return _carrottype;
}
set
{
if (value != _carrottype)
{
_carrottype = value;
NotifyPropertyChanged("CarrotT");
}
}
}
}
Now, in the code behind I'm binding to a list of Foods, like so, so that it gets the exact food hierarchy from the first page, NB: Items is a list of food that contains Subparts(Foods->Veges->carrots):
public partial class Subpart : PhoneApplicationPage
{
Food ourItem;
public Subpart()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
int index = int.Parse(selectedIndex);
ourItem = App.ViewModel.Items[index];
DataContext = ourItem;
}
}
}
And finally, my xaml binding for the 3rd page:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<ScrollViewer>
<ListBox x:Name="FileList"
ItemsSource="{Binding Path=Carrot}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource PhoneTextLargeStyle}"
x:Name="ContentText"
Text="{Binding CarrotTypeName}"
TextWrapping="Wrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
I'm trying to bind to the CarrotTypeName of a particular Carrot in a list of a vegetables which is in a list of Food( something like that).When I run the code, the index in the code is selecting based on the Items(list of food), not from the veges. Thanks if you understood my challenge.
The solution was to add an ID property to each of the classes(food, vegetable,carrots). Then in the SelectionChanged event of the Vege.xaml, i did this:
private void VegeListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (VegeListBox.SelectedIndex == -1)
return;
//Make the selected item in the VegeListBox an instance of a Vegetable
Vegetable selectedVege = (sender as ListBox).SelectedItem as Vegetable;
// Navigate to the new page
if (selectedVege != null)
{
//Navigate to the Carrot page sending the ID property of the selectedVege as a parameter query
NavigationService.Navigate(new Uri(string.Format("/Carrot.xaml?parameter={0}", selectedVege.ID), UriKind.Relative));
}
// Reset selected index to -1 (no selection)
VegeListBox.SelectedIndex = -1;
}
NOTE:In my ViewModel i had created a list of Vegetables(with each vegetable containing a list of Carrots) called VegeItems Then in the Carrot.xaml.cs page, you do this on the onNavigatedTo event:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string parameter = this.NavigationContext.QueryString["parameter"];
Vegetable vegeItem = null;
int VegeId = -1;
if (int.TryParse(parameter, out VegeId))
{
Debug.WriteLine(VegeId);
vegeItem = App.ViewModel.VegeItems.FirstOrDefault(c => c.ID == VegeId);
DataContext = vegeItem;
}
}
Then in the Carrots.xaml, in the ItemSource of the listbox, i put binding to the Carrot(List of carrots) property of the Vegetable class like so:
<ListBox x:Name="FileList"
ItemsSource="{Binding Path=Carrot}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource PhoneTextLargeStyle}"
x:Name="ContentText"
Text="{Binding CarrotTypeName}"
TextWrapping="Wrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Windows 8 TextBlock in DataTemplate

<FlipView Name="flipView"
AutomationProperties.AutomationId="ItemsFlipView"
AutomationProperties.Name="Item Details"
TabIndex="1"
Grid.Row="1"
ItemsSource="{Binding}" Style="{StaticResource FlipViewStyle1}">
<TextBlock Name="answerT" Text="{Binding question}"/>
<FlipView.ItemContainerStyle>
<Style TargetType="FlipViewItem">
<Setter Property="Margin" Value="0,137,0,0"/>
</Style>
</FlipView.ItemContainerStyle>
<FlipView.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="flipTxt" Text="{Binding question}"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I have the above FlipView in XAML defined. I want to get the information that i have in the "flipTxt" TextBlock in a string in C#.
Tried with VisualTreeHelper but i can't seem to understand exactly how it works.
As well, tried to create another textblock (answerT) that would read the same info and get the text from that one. Didn't work either.
Thanks
LE:
This is how i did the binding, i get the data from MobileService.
private IMobileServiceTable<myObj> obj_tb = App.MobileService.GetTable<myObj>();
private ObservableCollection<myObj> obj_it;
var res= await obj_tb.ToListAsync();
obj_it = new ObservableCollection<myObj(res);
flipView.ItemsSource = obj_it;
Providing your FlipView is binding to its collection correctly you can access the SelectedItem in code on different events eg SelectionChanged event
private void flipView_SelectionChanged(object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
{
if (flipView != null)
{
var item = flipView.SelectedItem as MyObj;
string question = item.Question;
string answer = item.Answer;
}
}
Possible MyObj
public class MyObj
{
public string Question { get; set; }
public string Answer { get; set; }
}
or as youre using MobileServices you would probably have this if using Json.NET
public class MyObj
{
[JsonProperty(PropertyName = "Question")
public string Question { get; set; }
[JsonProperty(PropertyName = "Answer")]
public string Answer { get; set; }
}

Categories

Resources