ListView selected Item binding not work - xaml

I have a listview in uwp , and a view model that declare pataient_List and selected_patient in this. my listview show itemsource but I don't know why my listview do not show selected item.
<ListView ItemsSource="{Binding pataient_List}"
SelectedItem="{Binding selected_patient, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding name_to_show_menu, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
viewmodel is
public class patient_view_model : notify_property_changed_base
{
public patient_view_model(patient patient_param)
{
pataient_List = new ObservableCollection<patient>();
load_patient(); // this function put patients in pataient_List
selected_patient = patient_param;
}
public patient selected_patient
{
get { return _selected_patient; }
set
{
if (_selected_patient != value)
{
_selected_patient = value;
RasiePropertyChanged();
}
}
}
public ObservableCollection<patient> pataient_List { set; get; }

One cause could be that the selected item must be one of the objects in the pataient_List.
Another cause is perhaps because you're setting the selected_patient in the constructor of the view model which is definitely before you bind the view model to the view. So, why not trying to set the selected_patient after you bind the view model to the view.

Forget about the ItemTemplate in the ListView.
<ListView ItemsSource="{Binding pataient_List}"
SelectedItem="{Binding selected_patient, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="Black">
</ListView>
.NET doesn't have a clue about how you want your data to be displayed, so it just calls the ToString() method on each object and uses that to represent the item. Override the ToString() method in the patient object to display what you need. Here is the code:
public class patient
{
public string name_to_show_menu;
public override string ToString()
{
return this.name_to_show_menu;
}
}

I solve issue with this one answer.
public override bool Equals(object obj)
{
if (this.name_to_show_menu == (obj as patient).name_to_show_menu)
return true;
else
return false;
}

Related

XAML ListView in ListView

Is it possible to make a ListViewin a ListView and if yes is it even possible to bind data in both of them? I already tried it but it wont work the first List is shown as i want but the second is not shown.
The Code Looks kind of like this:
<ListView ItemSource="{Binding Item}" x:Name="ListA">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Day}"/>
<ListView x:Name="ListB" ItemSoruce="{Binding Item}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Time}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
C#
listA.ItemsSource = timebooking.TimeBookingDataPeriod.TimeBookingData;
Hope sombody can help me :)
First of all, you should either go for a binding ItemSource={Binding Item} or setting the ItemSource in code listA.ItemsSource = ... as one overwrites the other. So I'll ignore the fact that you're trying to set it in code and go with the binding (which means you have a datacontext set on your view).
<ListView ItemSource="{Binding WeekDays}" x:Name="ListA">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Day}"/>
<ListView x:Name="ListB" ItemSource="{Binding TimesOfDay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Time}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I've changed your first ItemSource to WeekDays and the second ItemSource to TimesOfDay for clarity. This to explain the way how binding and datacontexts work.
The outer ListView (ListA) inherits its DataContext from the outer items, most likely your page / usercontrol.
In your ListViewItem, the datacontext is changed to a single item in the WeekDays collection. => every property bound under this tree has to be in a WeekDay object.
The inner ListView (ListB) inherits its DataContext from the ListViewItem.
In the ListViewItem, the DataContext is changed to a single item in the TimesOfDay collection.
Every ListView is a new level of objects. So for my sample to work, you need following class structure, not that I'll simplify the code and just use properties (while you should correctly implement INotifyPropertyChanged for UI updates).
public class SampleViewModel : INotifyPropertyChanged
{
public ObservableCollection<WeekDay> WeekDays { get; set; } // first listview
}
public class WeekDay
{
public string Day { get; set; }
public ObservableCollection<TimeOfDay> TimesOfDay { get; set; } // second listview
}
public class TimeOfDay
{
public string Time { get; set; }
}
If you want to use 2 properties from the page's viewmodel, you'll have to use an element binding in ListB. But this is only for scenarios were the items in the inner listview are not correlated to the ones in the outer listview.
{Binding ElementName=ListA, Path=DataContext.ItemsForB}
ItemsSource not ItemSource
Here is an example:
public class ClassB
{
public string Name { get; set; }
public ObservableCollection<ClassA>classAList { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ClassB"/> class.
/// </summary>
public ClassB()
{
Name = String.Empty;
classAList = new ObservableCollection<ClassA>();
}
}
public class ClassA
{
public string Caption { get; set; }
}
Create list:
ObservableCollection<ClassB> list = new ObservableCollection<ClassB>();
Init list:
ClassB item1 = new ClassB() { Name = "listAItem1" };
item1.classAList.Add(new ClassA { Caption = "listBItem1" });
item1.classAList.Add(new ClassA { Caption = "listBItem2" });
item1.classAList.Add(new ClassA { Caption = "listBItem3" });
item1.classAList.Add(new ClassA { Caption = "listBItem4" });
item1.classAList.Add(new ClassA { Caption = "listBItem5" });
list.Add(item1);
ClassB item2 = new ClassB() { Name = "listAItem1" };
item2.classAList.Add(new ClassA { Caption = "listBItem1" });
item2.classAList.Add(new ClassA { Caption = "listBItem2" });
item2.classAList.Add(new ClassA { Caption = "listBItem3" });
item2.classAList.Add(new ClassA { Caption = "listBItem4" });
item2.classAList.Add(new ClassA { Caption = "listBItem5" });
list.Add(item1);
this.DataContext = list;
and XAML:
<ListView ItemsSource="{Binding}" x:Name="ListA">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="Day"/>
<ListView x:Name="ListB" ItemsSource="{Binding classAList}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Caption}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
It seems you want to create a grouped list, in this case is better to use gridview with groups:
Good step by step tutorial for grouped gridview

Binding multiple sources in listview

I am trying to learn XAML with WINRT and I have a question about binding and viewmodels.
I have an two classes EmployeeList and DownloadableEmployee:
public sealed class EmployeeList
{
public IReadOnlyList<DownloadableEmployee> DownloadableEmployees { get; }
}
public sealed class DownloadableEmployee
{
public System.Boolean IsSelected { get; set; }
public System.String Name { get; }
//method
public IAsyncOperation<IRandomAccessStreamWithContentType> GetEmployeePicAsync();
}
I have binded the EmployeeList to a Multi Selectable ListView displaying employee Names and Pictures. A user can now select / deselect individual employee in the ListView.
To achieve that, I've have created a DownloadableItem class that acts as a ViewModel which is binded to my listview EmployeeLV.
public class DownloadableItemVM
{
public string Name
{
get;
private set;
}
public IRandomAccessStreamWithContentType EnmployeePic
{
get;
private set;
}
public DownloadableItem(string name, IRandomAccessStreamWithContentType thumbnail)
{
Name = name;
Thumbnail = thumbnail;
}
}
ObservableCollection<DownloadableItemVM> employeesToDownload = new ObservableCollection<DownloadableItemVM>();
// set source to ListView
EmployeeLV.ItemsSource = employeesToDownload;
foreach (DownloadableEmployee item in EmployeeList.DownloadableEmployees)
{
IRandomAccessStreamWithContentType stream = await item.GetEmployeePicAsync();
employeesToDownload.Add(new DownloadableItemVM(item.Name, stream));
}
My List View
<ListView x:Name="employeeLV" SelectionMode="Multiple" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Thumbnail}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Question XAML experts:
My ListView already binds to my custom View Model class DownloadableItemVM and properly displays the name and photo of each employee.
But now I have a problem because I need to "bind" each selected item in My ListView back to DownloadableEmployee.IsSelected such that when a user selects an employee, their "IsSelected" gets set to true and vice versa when they deselect.
How should I go about doing this?
Why not to have all DownloadableEmployee object inside your DownloadableItemVM, and bind to name, picture, etc. through this object ? E.g.
public class DownloadableItemVM
{
...
public DownloadableEmployee Employee
{
get;
private set;
}
...
public DownloadableItem(DownloadableEmployee employee, IRandomAccessStreamWithContentType thumbnail)
{
Employee= employee;
Thumbnail = thumbnail;
}
...
}
<ListView x:Name="employeeLV" SelectionMode="Multiple" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Thumbnail}"/>
<TextBlock Text="{Binding Employee.Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
With this approach you can reach your IsSelected prop through Employee object. Is this suitable for you ?

Different ItemSources for Panorama TitleTemplate, HeaderTemplate and ItemTemplate

I have a Panorama that has ItemSource set to an ObservableCollection which is created in the viewmodel
In the ViewModel.cs
public ObservableCollection<UserSchema> SeriesData;
private string _HeaderTitle;
public string HeaderTitle
{
get
{
return _HeaderTitle;
}
private set
{
_HeaderTitle = value;
NotifyPropertyChanged("HeaderTitle");
}
}
The value from HeaderTitle comes from HeaderSchema class's Title property (see below). This is set elsewhere in the viewmodel constructor not shown here.
UserSchema.cs contains the UserSchema which has implemented INotifyProperyChanged and has two properties. I have implemented the public getter and setter
private string _objectname;
private string _objectpath;
public string ObjectName
{
get
{
return _objectName;
}
set
{
_objectName = value;
NotifyPropertyChanged("ObjectName");
}
}
Similar code for _objectPath property also.
I have another HeaderSchema.cs that has also implemented INotifyProperyChanged and has two properties. I have implemented the public getter and setter
private string _Title;
public string Title
{
get
{
return _Title;
}
set
{
_Title = value;
NotifyPropertyChanged("Title");
}
}
Once again I have created a public get and set property for above as Title
Now in MainPage.xaml I have set the Panaroma ItemSource to SeriesData, elsewhere in the code behind I have set the DataContext to the viewmodel.
<controls:Panorama x:Name="SerPan" ItemsSource="{Binding SeriesData}">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<Grid x:Name="grid">
<TextBlock Text="{Binding ObjectName}">
</TextBlock>
</Grid>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ObjectPath}"/>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
This works very well and I get the correct output.
What I would like is to set a Title to the Panorama and I want to get the text from HeaderTitle property from viewmodel.
Something like the below, but the problem is HeaderTitle is a different property and not part of SeriesData which is the ItemSource for panorama.
<controls:Panorama.TitleTemplate>
<DataTemplate>
<TextBlock Text="{Binding HeaderTitle}"> //does not work.
</TextBlock>
</DataTemplate>
</controls:Panorama.TitleTemplate>
If your ViewModel is the DataContext of your Panorama control you can access it via ElementName Binding:
SerPan.DataContext = myViewModelInstance;
<phone:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=SerPan, Path=DataContext.HeaderTitle}" />
</DataTemplate>
</phone:Panorama.HeaderTemplate>

Xaml two way binding of textbox to observable collection

In my WP8 app I have a class, which has a ObservableCollection<ObservableCollection<int>> property called Matrix.
I want to display these matrices using items control.
<ItemsControl ItemsSource="{Binding FirstMatrix.Matrix}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The code works as far as displaying is concerned (it's filled with zeros which is a default value). But I also want to allow changes in TextBoxes which would be reflected in Matrix property - now the TextBoxes can't be changed, because their value is bound one way to Matrix cells I guess. I tried setting <TextBox Text="{Binding Mode=TwoWay}" />or sth similar but it doesn't seem to work.
Any ideas how should the data be bound ?
EDIT:
I have implemented the INotifyPropertyChanged.
Here is a part of my class:
public partial class CalcMatrix : INotifyPropertyChanged
{
public ObservableCollection<ObservableCollection<int>> Matrix
{
get { return _matrix; }
set
{
_matrix = value;
OnPropertyChanged("Matrix");
}
}
private ObservableCollection<ObservableCollection<int>> _matrix;
private void OnPropertyChanged(string argName)
{
var handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs(argName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
I think the reason the TexBoxes don't change is because the binding is one-way - the Text is always what is inside the Matrix. I believe that i should somehow change the XAML binding to TwoWay or something but don't know how. Any ideas ?
Two way mode binding require path (why? see this SO answer), so you can't do it just like {Binding Mode=TwoWay}, it has to be something like {Binding SomePath, Mode=TwoWay}. Therefore, in this case you have to wrap matrix item to be some class instead of plain int and put that int as property's value of that class.
//your Matrix property type become:
...
public ObservableCollection<ObservableCollection<MatrixElement>> Matrix
...
//MatrixElement class is something like:
public class MatrixElement : INotifyPropertyChanged
{
private int _value;
public int Value
{
get { return _value; }
set {
_value = value;
OnPropertyChanged("Value");
}
}
....
}
//then you can bind TextBox in two way mode
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value, Mode=TwoWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
...
The reason it didnt work is that the itemsource is a list of Matrix and you are not making any changes to the list iteself like adding or removing from a list instead you are changing a property of the item present in list I assume you are using an ObservableCollection....
So you need to implement a INotifyPropertyChanged interface to tell the UI that Hey I am changed please update yourself....
class YourClass : INotifyPropertyChanged
{
private string yourProperty;
public string YourPropety{
get{
return yourProperty;
}
set{
if (value != this.yourProperty)
{
this.yourProperty = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Multiselect drop down for silverlight4

I m looking out for Multiselect drop down for silverlight4, one available at codeproject is targetted for silverlight3.
Any links is highly appreciated.
If you want to display checkboxes as items of a comboBox, a simple DataTemplate shoud work:
<ComboBox Name="combo" >
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked,Mode=TwoWay}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Now on your code behind create an ObservableCollection ChekItem is a basic class:
public class CheckItem
{
public string Text { get; set; }
public bool IsChecked { get; set; }
}
and associate it to your comboBox ItemsSource. If you want to know what items are checked, is simple:
var checkedItems = myList.Where(i => i.IsChecked == true);