WPF Accessing Items inside Listbox which has a UserControl as ItemTemplate - wpf

I have Window that has a ListBox
ListBox(MyListBox) has a DataTable for its DataContext
ListBox's ItemSource is : {Binding}
Listbox has a UserControl(MyUserControl) as DataTemplate
UserControl has RadioButtons and TextBoxes (At first They're filled with values from DataTable and then user can change them)
Window has one Submit Button
What I want to do is, when user clicks the submit button
For each ListBox Item, get the values form UserControl's TextBoxes and RadioButtons.
I was using that method for this job :
foreach(var element in MyListBox.Items)
{
var border = MyListBox.ItemContainerGenerator.ContainerFromItem(element)as FrameworkElement;
MyUserControl currentControl = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(myBorder,0) as Border,0)as ContentPresenter,0)as MyUserControl;
//And use currentControl
}
I realised nothing when using 3-5 items in Listbox. But when I used much more items, I saw that "var border" gets "null" after some elements looped in foreach function.
I found the reason here :
ListView.ItemContainerGenerator.ContainerFromItem(item) return null after 20 items
So what can I do now? I want to access all items and get their values sitting on user controls.
Thanks

You should use objects who implement INotifyPropertyChanged and bind an ObservableCollection of it to the ItemSource
And then you can get all the list of items.
Here some quick links from MSDN to get more informations
How to: Implement Property Change Notification
Binding Sources Overview
You should google for some tutorials about this.

Zied's post is a solution for this problem. But I did the following for my project:
I realised that there's no need to use UserControl as DataTemplate in my project. So I removed ListBox's DataTemplate.
I removed MyListBox.DataContext = myDataTable and used this:
foreach(DataRow dr in myDataTable.Rows)
{
MyUserControl muc = new MyUserControl(dr);
myListBox.Items.Add(muc);
}
I took DataRow in my UserControl's constructor and did what I want.
And at last I could access my UserControls in ListBox by using :
foreach(MyUserControl muc in
myListBox)
{
//do what you want
}
Easy huh? :)

Related

WPF MVVM Listview itemsource binding with list in a class property

I have a page with two parts :
A Listview with itemsource binded with a class, ObservableCollection "Patients" loaded with "Patient" class.
Under the Listview are Textboxes binded with the selecteditem Patient. Everything works without writing any code in the page, except in selection_changed to scroll to selected item.
A second Listview must display the details "Visites" from the selected "Patient".
The application works in a MVVM Framework with a Viewmodel containing the properties for the page.
The problem is to make the relation between the two ListView. I tried first building the second list "Visites" in the NotifyPropertyChanged event :
if (Patient.ID > 0)
{
LoadVisite(Patient.ID); // fill the details list "Visites"
NotifyPropertyChanged("Visites");
}
No delail is shown when "Patient" is selected.
I tried another solution inserting the list of details in the master class "Patient like this :
public Class Patient
...
public ObservableCollection<ClsVisite> Visites
{
get
{
return _visites;
}
set
{
_visites = value;
}
}
// WDABase class to open the database and load data connection
WDABase wd = new WDABase();
wd.LoadListeVisites(ID, _visites); //ID is the relation beween the two tables
}
}
Now I try to create the Listview detail itemsource in the XAML like this :
<ListView Name="ListeVisites" ItemsSource="{Binding Path=Patient.Visites}" SelectedItem="{Binding Visite}">
No details where shown.
The unique solution I found was to add some code in the selection_changed event of the master Listview like this (in this case the listviews are in two different frame) :
private void ListePatients_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ListePatients.ScrollIntoView(ListePatients.SelectedItem);
if(ListePatients.SelectedItem != null)
{
var w1 = ((System.Windows.FrameworkElement)App.Current.MainWindow.Content).Parent;
Frame pageVisite = (w1 as MainWindow).Visit;
var w2 = (System.Windows.FrameworkElement)pageVisite.Content;
ListView Lv = (w2 as Visite).ListeVisites;
Lv.ItemsSource = (ListePatients.SelectedItem as ClsPatient).Visites;
}
}
And it's works but is there another elegant solution to bind the itemsource of the details Listview ?
Thanks for helping me.
Jean-Marie
I found the solution to my problem.
The Reason the details were not displayed is because the frame used for the listview is not common with the master frame.
I discover that when I display the details frame the "Patient" object contains only null. I Don't know why but I read about sharing ViewModel and now I use a common one in App.xaml and I Don't need to specify the itemsource for the details Listview in code. I put in XAML itemsource={Binding Patient.Visites} and everything works.

WPF window inserting an array into DataGrid

WPF window in C# doesn't have option of Inserting something into DataGrid immediately, like as WinForms Form
DataGridView.Rows.Add(whatever)
What is alternative for this code 👆?
So how can I insert an array into DataGridView in WPF window?
You can actually add objects directly to the Items property of the DataGrid:
dataGrid.Items.Add(whatever);
But if you want to be able to edit the items, you should set or bind the ItemsSource property to an IList:
dataGrid.ItemsSource = new List<object> { whatever };
You need to bind the DataGrid to an ObservableCollection. If you insert into the ObservableCollection, it'll appear on the UI

MVVM light multiple instances of usercontrol

How can I get multiple instances of a usercontrol without the viewmodel being shared? Each usercontrol (and thus viewmodel) should be an instance of its own.
I have read a solution in this question: MVVMLight UserControl View Model-Create new Instance of User control for each view but I cannot get it to work!
I have a listview and a tabcontrol. When I click an item of the listview a new tab must be created with as content the usercontrol which holds information from the selected listitem. The problem is that when selecting multiple items all the items contain the information from the last selected item.
This is my viewmodellocator:
public DossierDetailViewModel DossierDetail
{
get
{
return new DossierDetailViewModel();
}
}
And I call the new usercontrol like this:
DossierDetailViewModel newDossier = new DossierDetailViewModel();
newDossier.TabName = SelectedDossier.Omschrijving;
this.OpenDossiers.Add(newDossier);
Messenger.Default.Send<DTO.Dossier.Dossier>(SelectedDossier, "SetDossier");
EDIT:
Is there no one who can help me or put me in the right direction? :(
The answer of this problem can be found here: https://mvvmlight.codeplex.com/discussions/577555

TabControl - databinding TabItem order

I've got a datababound TabControl and would like to bind the index of each TabItem to a corresponding property in my view model. The ItemsSource is an ObservableCollection, and I'm using Bea Stollnitz's Drag/Drop functionality to provide tab control re-ordering.
My gut feeling is that it should be able to be handled in the data template for the tab item header, but I haven't been able to get it working.
Your TabControl.ItemsSource should be bound to your collection, so to re-arrange the order of tab items, simply re-arrange the collection.
I've worked with Bea's drag/drop code before to create a TabControl that allowed users to drag/drop the tab items, and I think most of what was needed is in the code she provides. On drop, it removes the dragged object from it's parent collection, and inserts it to its new location in the drop target collection, which in your case is the same collection.
Edit
Based on your comment below about updating your ViewModel with the Tab Index, try using the CollectionChanged event.
void MyCollection_CollectionChanged(object sender, CollectionChangedEventArgs e)
{
foreach (var item in MyCollection)
item.TabIndex = MyCollection.IndexOf(item);
}

Binding to an ObservableCollection of UserControls

Simple Silverlight question: I have an ObservableCollection<MyObject> in my viewmodel. Every MyObject has a Label property. If I bind a ListBox to the collection and set DisplayMemberPath to Label, or set the ItemTemplate to a TextBlock that binds the Text property to Label, all works as expected.
If I change MyObject so it derives from a UserControl, the Label text no longer shows up in the ListBox; each item just shows up as a blank strip a few pixels tall. Why is this? There's obviously something I'm missing here about how different things get rendered.
The ListBox determines that the set of items in its ItemsSource are already UIElement instances and therefore decides to use those elements directly as the content of the ListBoxItem elements it creates.

Resources