WPF TreeView ItemsSource not keeping values - wpf

I am using a wpf treeview and binding the ItemsSource to an IEnumerable of my ViewModel that has an IsChecked Property. I am binding a checkbox to this value with a Mode of TwoWay. I can see when I step through the program that it is setting this value properly on my ViewModel when I check the checkbox.
I then have a Menu Item that "Runs Checked". In this method I have a foreach loop that runs through the ItemsSource as IEnumerable of ViewModel looking for IsChecked = true to queue up the checked items to be run by a separate program. As such:
foreach (AccountViewModel account in tvClientList.ItemsSource as IEnumerable<AccountViewModel>)
{
if (account.IsChecked)
{
context.Queues.InsertOnSubmit(new Queue {Id = account.Id});
}
}
However, account.IsChecked is always false. Why is this?

i would check the following.
does the setter of AccountViewModel.Ischecked is called when clicking the treeview checkbox. if no - then thats the problem if yes you should look at your collection bindings.
debug your foreach and check wether the treeviewitemssource is the collection you expect.
maybe you can post your bindings, if that all no help.
ps: dont access your View controls directly if you use viewmodels/mvvm.

Just for anyone else encountering this issue. ItemsSource returns a new set of data, Items, however contains the current set of data.

Related

Databinding causing other functions on page not to work when filling datagrid

I have a datagrid in my View. The datagrid's itemssource property is bound as such
ItemsSource="{Binding}"
Addtionally in the codebehind I have set datacontext by doing the following:
DataContext = ProcedureDatabaseViewModel.Procedures();
The Procedures function in the viewmodel successfully outputs a list which the DataGrid successfully displays.
The issue now is that the datacontext of the entire page is now set to the above. The result of this is that other elements that interect with the VM no longer work. I.E. buttons with commands that are found in the VM. I have tried removing the setting of the datacontext in the code behind but cannot figure out how to populate the datagrid otherwise. Please note that when the DataContext is not set in the code behind the context is changed to the VM, I believe, and thus, the other elements begin working again. I have tried changing the Itemssource property to target the list of objects that I wish to populate the datagrid with but it hasnt worked.
The list is
List<procedure> Procedures
and it is in the ProdureDatabaseViewModel. I tried to target it as
ItemsSource="{Binding ProdureDatabaseViewModel.Procedures}"
But this has not worked either.
Can someone please advise me on the correct way to do this?
The cleanest way is to use ItemsSource to bind your Procedures collection to your DataGrid. For this to work, Procedures has to be a Property. To avoid further issues, use an ObservableCollection. It should look like this:
ObservableCollection<procedure> Procedures { get; set; }
Then you should be able to simply bind it via
ItemsSource="{Binding Procedures}"
I prefer to set the DataContext in the constructor of the view to the complete ViewModel (which I created for this special view).
So I do something like this in the constructor of the view:
public View(ProcedureDatabaseViewModel viewModel)
{
this.DataContext = viewModel;
}
This way everything else should still work and you can use more than just the procedures.
Next you bind the procedures to your datagrid:
ItemsSource="{Binding ProcedureList}"
Do note that for this to work, "Procedures" needs to be a property. It's not clear in your question if it is a function, a property or just a simple class member. If it is a function, you can do it like this in your view model:
public List<procedure> ProcedureList
{
get { return this.Procedures(); }
}
I have tried removing the setting of the datacontext in the code
behind but cannot figure out how to populate the datagrid otherwise.
You can set the DataContext of your DataGrid separately like so, MyDataGrid.DataContext = ProcedureDatabaseViewModel.Procedures();.
And apply separate DataContext for your Page.

Clearing selecteditem of listbox (which is bound to collection of objects) with MVVM

I have a listbox with silverlight 4. I have the list bound to a list of objects.
1.) The SelectedValue property is bound to a public property of the viewmodel called Current. How do i clear the selection? I have tried setting the value of Current to null. Well, this clears the selection however it also breaks binding in the edit form which has a combobox bound to a property of 'Current'. Textboxes which are bound to Current.FirstName etc. are working ok however the comboboxes do not function after I set the Current object to null.
2.) how do i load the form without the first item being selected?
Found a work around for this bug in Silverlight:
// Bug in SL listbox prevents SelectedIndex = -1 from unselected.
// Workaround is to use DispatcherBeginInvoke to do it async. Found
// work around here:
// http://sharplogic.com/blogs/rdavis/PermaLink,guid,2f5bbfa1-4878-490f-967d-bf00bc04dfde.aspx
Dispatcher.BeginInvoke(() => { QuickItemsListBox.SelectedIndex = -1; });
More details here:
http://sharplogic.com/blogs/rdavis/PermaLink,guid,2f5bbfa1-4878-490f-967d-bf00bc04dfde.aspx
Not sure when it was fixed but VoodooChild's answer works now in Silverlight 5. Passing this along in case others are looking.
yourCB.selectedIndex = -1;
Try:
yourCB.SelectedIndex = -1;

Silverlight DataGrid binding issues after refreshing or setting selectedIndex=-1

I have a datagrid and a combobox on the form. The combobox is bound to the selectedItem of the datagrid.
I load things fine and if i select different rows the combobox is updated correcly.
If however I set datagrid.selectedIndex=-1 after it loads (so that the first row is not selected) the combobox binding no longer works. This is a problem.
I also have another scenario where the exact thing occurs. If i filter the datagrid, the binding to the combobox also stops working.
I am binding the datagrid to a CollectionViewSource like the following where _codes is an ObservableCollection
_ocvsCode = (CollectionViewSource)this.Resources["cvsCode"];
_ocvsCode.Source = _codes;
dataGrid1.ItemsSource = _ocvsCode.View;
I don't know why the binding to the combobox is failing after some operation on the datagrid.
The appropriate solution in this case is to bind the datagrid selecteditem to some variable, and to then bind the other controls to that variable as well. It is generally bad practice to bind UIElement properties directly to other UIElement properties. This will also make debugging the problem you seem to be having with coercing the selecteditem property to the combo-box.
I have come across the same problem, where a ComboBox is bound to a the value of the SelectedItem of a DataGrid.
The ComboBox control breaks when the data it is binding becomes null, and never recovers. I'm not sure why that is, but it seems to me to be a bug. When the DataGrid sorts a column, it first sets its SelectedItem to null, performs the sort, and then resets SelectedItem to the original value. When the SelectedItem becomes null, the ComboBox breaks.
Here's my work around:
Create a SelectedItem property on your class that is being used for the DataContext. Perform a check on the setter that prevents it from being set to null. Bind against this property with your DataGrid and ComboBox.
public YourItem SelectedItem
{
get { return _selectedItem; }
set
{
if (value == _selectedItem || value == null)
return;
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}

WPF Accessing Items inside Listbox which has a UserControl as ItemTemplate

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? :)

Silverlight listbox won't update with new itemsource

I have a listbox which is bound to a generic list, whenever I removed an item from the generic list and rebind it to the listbox it still shows the deleted items. Here is the code :
InventoryList.Remove(currInv);
lstSubMenu.ItemsSource = InventoryList;
lstSubMenu.DisplayMemberPath = "InventoryItemName";
I checked the generic list and the item is being removed and there doesn't seem to be any errors in the output window.
Set the ItemsSource = null before you set it to be InventoryList.
However, it is generally better practice to set the ItemsSource property once and never again. You can do this by using an ObservableCollection. Once you do this you can add/remove to your heart's content and not have to worry about the binding target not getting updated.

Resources