Control inside datatemplate in ListBox UWP xaml - c#

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.

Related

xamarin listview get selected item

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;

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>

Databinding in C# , XAML. Databound Element 1 displays but databound element 2 does not

I have a small WPF application I'm working on which I have greatly simplified here to illustrate the problem I am having.
This is the code behind for the app:
namespace RadioRecordingMonitor
{
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
findStationNumber();
findRecordingFailTop();
}
public void findStationNumber()
{
var listlength = 50;
this.DataContext = new stationAmount() { stationAmountTextData = listlength };
}
public void findRecordingFailTop()
{
var errorlenght = 20;
this.DataContext = new errorAmount() { errorAmountTextData = errorlenght };
}
public class stationAmount
{
public int stationAmountTextData { get; set; }
}
public class errorAmount
{
public int errorAmountTextData { get; set; }
}
}
}
And below is the XAML
<Window x:Class="RadioRecordingMonitor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Radio Recording Monitor" Width="300" Background="#ECF0EF" Height="300"
Loaded="Window_Loaded" >
<Grid>
<TextBlock DataContext="{Binding}" >
<Run Text="Total stations not recording:"/>
<Run Text="{Binding errorAmountTextData}"/>
<Run Text=" /"/>
<Run Text="{Binding stationAmountTextData}"/>
</TextBlock>
</Grid>
</Window>
The problem I am having is that only one of the databound elements displays at any one time. As it is only the errorAmountTextData element displays and if I remove the findRecordingFailTop(); method the stationAmountTextData element does display which tells me that my variable is being passed through to the XAML side.
Why is this happening and what can I do to fix the issue?
You are assigning an entirely different class to the DataContext each time, thereby replacing it each time you assign to it.
Instead, just have one class;
public class Amounts
{
public int stationAmountTextData { get; set; }
public int errorAmountTextData { get; set; }
}
Then, just assign that class to your DataContext
var myAmounts = new Amounts { stationAmountTextData = 123, errorAmountTextData = 456 };
this.DataContext = myAmounts;
When you change the datacontext to new errorAmount(), the datacontext for the whole page changes and will not work because errorAmountTextData is not found in errorAmount instance.
Keep both the properties in one class and set that as datacontext which should work fine..

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