WPF add/edit/delete treeview nodes in MVVM style - wpf

I am new to MVVM and WPF treeview. I have done some research and have read the Josh Smith article on MVVM, and this, and this.
I think I have no problem creating the treeview in WPF. The thing is on my app, the left panel is the tree view, the right panel will display some properties of the selected tree view node, which user can click a button to edit the properties and save it to the data source (and potentially will affect the treeview item). In addition, user would be able to add/delete child node/grandchild node.
I can't seem to find any article/example to implement this using MVVM.
I am currently thinking that in the view models for the child node and grandchild node, I shall add a public property which points to a Usercontrol. The right panel will bind to the treeview's selected item's Usercontrol. The thing is, when user adds a child node/grand child node, the right panel will be used to let user fill in information and save. I am not sure whether it will affect the binding.
And other issues like editing the properties of a tree node will mean to copy all the child node info of the node to the new node and delete the old node from the tree and add the new node to the tree?
Can someone point me to any good articles on a similar implementation or give a rough idea on the issue that I should take note etc?
Thank you very much.
Angela

A lot depends on your setup but here is a way I have used before.
Note that you might need a ChildPropertyChanged event type of thing (I made that name up) to bubble up changes in the tree to the root of the tree.
To add a node
I created a ViewModel that contains:
a property for the tree data collection (probably a reference to the root node)
a property called NewNode.
a property called CurrentNode
a command that adds the NewNode to the CurrentNode: AddCommand
In the View:
Bind the TreeView to the tree data collection
Bind the SelectedItem of the TreeView to the CurrentNode
Bind the controls with the data for the new node to the NewNode properties
Bind a button to the AddCommand
In the AddCommand:
Add the NewNode to the CurrentNode and re-initialize the NewNode property.
To edit a node
In the ViewModel
add a command: UpdateCommand
add a command: EditCommand
In the View
bind some edit controls to the CurrentNode's properties (OneWay binding)
bind a button to the EditCommand
bind a button to the UpdateCommand
In the EditCommand:
make the edit controls and update button visible (I use a State property to bind to, see Extra below)
In the UpdateCommand:
write the values of the edit controls to the SelectedNode
hide the edit controls (I use a State property to bind to, see Extra below)
To delete a node
In the Viewmodel
add a DeleteCommand
In the DeleteCommand:
remove the CurrentNode from the collection
Extra
I have found it very useful to implement IEditableObject on the ViewModel of a Node.
Using the methods of this interface you can add a cancel button to reverse the EditCommand. By adding a State property to the ViewModel of a Node (New, Modified, Deleted) you can track changes, know what updates to send to the model/database and you can bind the View to it to show/hide elements.

Related

Deleting or adding a node in WPF MVVM Treeview

I am new to these stuffs. Hence I request for your help.I want to delete and add a node to a treeview in WPF MVVM. I have managed to create the treeview using :
http://www.codeproject.com/Articles/354853/WPF-Organization-Chart-Hierarchy-MVVM-Application
but now I am not able to figure out how can I add/delete a node and then refresh the treeview.
Help is appreciated.
That is the problem with copying other people's code and not bothering to find out how it works. In WPF, we manage data elements, not UI elements, so to add another item into any UI container control, we simply add a data item into whichever data collection that is data bound to the ItemsSource property of the container control. In your linked article, you can see the following:
Tree View
The DataContext of the TreeView is the OrgTreeViewModel. We set the TreeView's ItemsSource to the Root property of the OrgTreeViewModel, which is the top-most node in the hierarchy.
It therefore seems as though you have a collection property named Root in your OrgTreeViewModel view model class. So, all you need to do to add a new item into your TreeView is to add a new data object into your Root collection. If that tutorial is any good, then the UI will automatically update, showing the new item.

WPF loading grid child based on treeview click

I'm developing a WPF C# app where I have a tree view control and if the user clicks on a node in the tree, a node-specific detail 'form' appears in a named Grid somewhere else in the form. If you click on a different node in the tree, the displayed detail form checks if the contents are saved, is dismissed, and a new detail form appears in it's place.
What I need is some starting advice. Can I still implement the forms as standalone xaml, then put some some of 'container' in the grid that I throw the form into as a child? Or just add the form as a grid child somehow. How do I programmatically load the form I want in the grid and communicate with it?
Thanks for any assistance!
Corey.
Use an event aggregator design pattern, see here for details:
http://martinfowler.com/eaaDev/EventAggregator.html
You can then have some other code which listens for the node change clicks via the event aggregator and response accordingly. This will decouple your code and make it more testable.
Am assuming you are using mvvm?
If not read up on it - will make it easier.
then you have your form with the treeview on it, bound to its itemsource on the view model.
Usually an items control like a treeview will have a selecteditem property on it.
Bind that to a property on your viewmodel which is of the type of objects contained in your treeview. Call this for example CurrentlySelectedItem.
Your details 'form' can be a control or whatever you want on the same form.
Now depending on how complete your object is - you have at least two options. If your object in the treeview has all the data you need already, then just bind the details to CurrentlySelectedItem.
Obviously it must implement INotifyPropertyChanged to tell the binding system to update the values.
If the object doesn't have enough info, then on the setter of CurrentlySelectedItem you can then fire a method to load the full object and then bind the details to that full object.
Alternativley, another popular approach, you could have the details form as a self contained control that subscribes to a message and when it recieves the message with the key of the treeview object, it loads the required info.

Dynamically Load UserControl using MVVM Light Toolkit

I searched this site and i found 2 Links
how to load wpf usercontrol in MVVM pattern
MVVM-Light: Load UserControl into Window
but still i cant find the answer to my problem and this link
MVVM-Light Locator Pattern and Reusable UserControl
i Didn't Understood.... so here is i am stating my problem which might help others struggling like me ......
I have a MainWindow which has 2 parts one has a TreeView(a
UserControl) and the other Displays different user controls(named DisplayPanel).... just like windows Explorer.
The Display Panel on the Right side will display different user controls on Clicking nodes of tree view.
and my TreeView is Itself a user Control.
How can i make this composite UI Work using MVVM. Also I am planning to use MVVM light Toolkit. Does this have something that can help...
An Example will be great
Thanks... :)
Edit
My TreeView in a UserControl I made a dependency property in the UserControl which catches the selected Item fo the tree view so that i can use this dependency property to populate the required view in the "MainView" ContentControl binding....as you advised me in the comments. Everything is till now
Problem is that i want to display data contained in the the selected item and i cannot set the DataContext of the UserControls(which will be displayed in right hand side) to the selected item as then i will not be able to use my view model for the respective usercontrol for commands and other operations
I tried to solve this too.... i used the Mediator (Messenger) in my TreeViewUserControl view model to send a Message to the Usercontrol's(the one that i need to display) view model . Message will be passed whenever the item is selected in the tree view. and message contains the selected node. I forgot to mention i set the datacontext of the UserControl to its view model so that i could display data
But using this approach the problem is that when the I click a type of node for the first time the data is not populated but if the same type of node is clicked again its populated. What’s happening is that UserControls object is availabe when the the tree item is clicked for the first time and Mediator sends the message. So Mediator is not able to pass the message to the userControl view model.....
I totally do not have ne idea to solve this further.... is my way if displaying user control right or I should do something that else....totally confused.....
You could try defining a DataTemplate for each type in the TreeView's ItemsSource and instead of having a specific UserControl on the right side, just bind to the TreeView's SelectedItem. Alternatively, you could use a DataTemplateSelector.
Edited for OP's Edit
Did you do this?
MainWindow has TreeView whose ItemsSource=Binding MainVM.Items.
MainWindow has ContentControl whose Content=Binding TreeView.SelectedItem.
Somewhere in project, have ResourceDictionary where each possible type in MainVM.Items has a DataTemplate defined?
Which ViewModel (MainVM or ItemVM) are you trying to use and why can't you use it?

Bind List of UControls to a Controls Children property?

I have got an ObservableCollection<Button> buttonList; (this can be any other control: TextBox, TextBlock or even a UserControl).
I want to bind this List via DataBinding to a parent control (lets say a Grid or a WrapPanel,...)
Is this somehow possible? Children property is read only.
I do not want to do this in the program code -> Dont iterate through the list and add every item to the children property.
I want to BIND the List to a parent control -> the View is automatically updated, every time I add a new Item to the List.
Any Ideas?
Use ItemsControl, and bind your collection to ItemsSource.
And don't forget to read Dr. WPF's articles: ItemsControl: A to Z. This is second time I'm mentioning this blog today here, but he really-really deserves to be mentioned in every post related to collection of items and bindings :).
Cheers, Anvaka.

Programmatically show expand arrow on Silverlight TreeView

I have a Silverlight TreeView control that I'm dynamically populating when a specific node is clicked. For example, I load the first generation (level) of nodes, then when the user clicks on one of the nodes, I use the Selected event to populate that node's children, etc, etc. I'm sending back from my database a bool value with each node value that indicates whether or not the new nodes have children nodes.
I am wanting to set the expand arrow to show in front of new nodes that have a child, but the catch is that its children will not be populated yet. I thought maybe setting the HasChild to my bool value, but HasChild is read-only. Any suggestions would be very much appreciated.
Just a add blank treeviewitem when it's collapsed just to show the arrow.
But when expanded by the user, clear that blank child, and do an async call to get the real children.
Set the UserState to the parent treeviewitem or id when doing the GetChildrenAsync call.
When they arrive, the UserState should be that parent treeviewitem or id, when you find that parent which you just set it's itemsource to the e.Result.
If you're familiar with dependency properties, you could create a dependency property that would be settable by you in code and gettable in the xaml so it could be bound to.
This would allow you to use a ValueConverter to render the visibility of the arrow.

Resources