✅ WPF - how to approach a treeview displaying different types at different levels via MVVM
I'm just learning WPF - so seeking some design advice. I'm designing a Visual Studio extension to view and edit Gists. Each type Gist has a collection of type GistFiles (Files property in a Gist):
I'll have 3 views inside the main View: GistsBrowser (user control=treeview), GistEditor (user control) and GistFileEditor (user control). I'm thinking I need to store the Collection of Gists in the MainViewModel, as different UserControls/ViewModels will need access to a shared GistsCollection to ensure synchronicity.
For the GistsBrowser, I need to make a specific treeview control to display all Gists at the root level which can be expanded to show all of the GistFiles within a Gist. There will be no further child levels.
Thus, this UserControl will need its own ViewModel (GistsBrowserViewModel). However, I'm stuck on a few things:
How to structure the Gists collection in MainViewModel. Not sure if I need to map the Github data objects onto my own models, or map them directly onto a viewmodel. Do I need a Gist/GistFile viewmodel? Also, this links with:
What data construct to use for the Gists collection and how to hook it up to a TreeView (given level 0 will be Gists and level 1 GistFiles)
I hope that makes some kind of sense. Any pointers for further reading/research would be appreciated.
52 Replies
To display data in a tree view you need to use hierarchical data templates
To display different data with their respective views define multiple hierarchical data templates in the resources tag of your treeview
You do not need a gistviewmodel per se
Thanks Denis. Funnily enough you type that just as I'm watching this:
https://youtu.be/U2ZvZwDZmJU?si=13ERFuQ2zmHBFlOB&t=3617
AngelSix
YouTube
C# WPF UI Tutorials: 03 - View Model MVVM Basics
Part of a series of tutorials on creating WPF applications in C#
Converts the previous TreeView demo application from code-behind to much better View Model MVVM application
Source code here: https://github.com/angelsix/youtube
So I'm thinking, my TreeViewModel would have a list of Gists, each of which contains a List of GistFiles. The DataBinding through the Hierarchical data template would bind to List<GistFile> and that should display items correctly?
forgive me - WPF/MVVM fries my brain a little
but I would need a GistViewModel and a GistFileView model as well
as I understand it?
Will the data be retrieved in real time and be updated constantly? Do you want to update the data or only read it?
Will retrieve the list of gists from github. Then, if the user changes data on the gist or gistfile detail views, then an indicator will show on a Save icon. The user will manually select save
That's the easy part!
It's ok, I've watched these tutorials too some time ago, and they fried my brain too
🤣
I think I;'m conceptusally there, tbh. Just need to give it a go
One thing I'm puzzled about is where I keep the ObservableCollection<GistViewModel> - I think I need to keep it in the MainViewModel, as teh GIstsBrowser, GistEditor and GistFileEditor will all need to access it
i.e all need to access the same data models
or dataviewmodels more speciically
does that sound about right?
Here are a few points.
Your viewmodel is the main source of data that comes in contact with a view.
Viewmodels expose models into the view, that represent data. There is no rule that would state - if a model must be observable, then you need a viewmodel to wrap it. So, here's a simple rule of thumb: what has logic and binds to the view is a viewmodel
What represents data and can, but doesn't necessarily have to observable is a model
I need to help with cooking, will come back to you l8r
thanks
Back.
Alright, will your application be a single window? Will you have multiple pages, dialog windows, etc.?
If it'll be a single window, then you can significantly simplify everything
You can have a MainWindow.xaml (or I usually rename it to MainWindowView, but be careful with that, VS can break your code after the rename) and a single MainWindowViewModel
yep - essentially single window (it's a VS ext - so will all be in a single tool Window)
source here if it helps: https://github.com/stigzler/VisGist
GitHub
GitHub - stigzler/VisGist
Contribute to stigzler/VisGist development by creating an account on GitHub.
the viewer, editor and file editor will all be within one window, right?
yep
and will be visible to the user at the same time? or will be switched between view -> editor -> file editor
at the moment - yes - GistsBrowser, GistEditor and GistFileEditor will all be visible at the same time
Let me dig a little deeper.
Given I open your tool, sign-in to GitHubs gist provider. I will presumably then see a list of my Gists via the GistsBrowser. By selecting a gist within the browser, its contents will be revealed in the GistEditor, correct?
Plus, another question, out of curiosity, are you using Fody Weaver or Community Toolkit MVVM?
Kind of. The tree view's root elements will be essentially be the Github Gist data object. You'll expand that and it will list all of the GistFiles linked with that Gist (GistFiles belong to one Gist only).
When you click a Gist, the editable detilas will opne in the gist editor (it's only two properties really)
When you click a GistFile - likelwise will happen in the GistFile editor (again - only couple/few fields)
just started using Community Toolkit MVVM
not very fmailiar with it yet
Very good, it actually helped me understand how to use MVVM properly
cool
If it is to be within a single window, then use a single viewmodel
you'll save yourself a ton of trouble
I'm thinking
ObservableCollection<GistViewModel>
in MainViewModel. GistVieModel
contains ObservableCollection<GistFileViewModel>
The cool thing about user controls is that when you place them within a window, or another user control, they inherit their parent's data context
Make it
Gist
instead of GistViewModel
because it is a model
it shouldn't have any logic
same goes for the GistFile
my recommendation from what I've gathered so far
So, you'll have a MainWindow.xaml + MainWindowViewModel as its data context
within the MainWindow.xaml you'll create some sort of grid layout and place your browser, editor and file editor user controlsoh. Ok - so have a local Gist and GistFile Model? I'm goign to store the 'original' (i.e. imported) Gist in the model or vm (whichever I use) for reference
Do you need to store the original?
Is it for undo/redo?
or "restore"?
fair point - I'll give that some thought - the update fucnton through the gItClient only need Ids etc - guess I won't need them
You can have that as a property of the respective model
You'll probably need it anyway
- MainWindow.xaml
- MainWindowViewModel.cs
- Gist.cs
- GistFile.cs
- GistsBrowserView.xaml
- GistsEditorView.xaml
- GistsFileEditorView.xaml
here's what I've gathered so far
Do you want your collections to be "reactive", or in other words, do you want changes to collections within your models visible instantly during the runtime of your tool?
If so, they must be observablecollections
only question is - when does a model become a view model? If I needed to include some logic in the data object (for example to generate a specific property) is it then a vm? For example, the Gist object is going to need some programmatic producting of its "Name" (or header in the TreeView) as it gets it from GistFile[0].Filename
There is no 'name' in the Github Gist
Models should be dumb objects containing data, that can be observable - so if you need logic, it must be a viewmodel. But again, should you really migrate your models into viewmodels? Where else can you place this logic?
yeah - I'm liking your tac - kiss principle
Maybe a converter in the view? Or some logic in the MainWindowViewModel upon retrieving the data from the API?
yes - guess I could examine the gist in a converter as it would have the GistFile[0] within it
Yeah, and separation of concerns
ok - this feels right. So keep try and keep to MainViewModel only where possible - Have an ObservabelCollection<Gist> in that vm and databind that to any browsers/editors
Models represent data, viewmodels do logic - get data, and expose it to the view
Yes
yeah - thanks - that's been really helpful. Dunno why I'm still struggling so much with WPF + MVVM - it's taking a mental shift that I'm struggling with
Once everything clicks, you'll love it
That's awesome man and that code matches what's in my head! Thanks again - top bloke!
And you put the rest in the viewmodels for loading the editor info and so on, and saving, etc.
To organize stuff I usually use
#regions
. It's a controversial feature of C#, that some devs use to hide large potions on code within their methods....
But if used right, you can organize your code quite well
Here's how I do it
Then you can collapse those regions to see what you need
I use it to organize a C# class structure - not bodies of methods or properties!!!ah yes - got region and comments on snippet shortcuts!
and I use consistent names
Ctrl+K, S I believe
Not sure right now
Thanks again - you've put me on track - sure it'll be plain sailing form here (!!?? - what could possibly go wrong?)
Navigation, communication between viewmodels, Dependency injection
Clean viewmodel design - zero references to GUI framework elements
Working with grouped, filtered, sorted collections in real time - collection view source
And 🥁
localization
So yeah.... there's a lot to learn lol
Plenty to keep me out of mischief
Keep at it, you'll master it all in no time
tbh - this is my first "right I'm gonna learn WPF/MVVM if it kills me" project
My first wpf project was total crap
and my attempt at mvvm was horrendeous
so, you're on the right track
and a great project btw
and things are already starting to click (commands, no code in the xmal code-behind, get the basic databinding concepts) and I can sense that it's good once you get there
the code behind still has a use in some cases
but you'll figure them out soon
thanks - nicked the idea - I did try forking some virtual abandonware - but his code was bonkers - he had view models for everything - just couldn't abide it in the end, so decided to make this my learn WPF MVVM starter project - ocotkit is suprisingly easy to use - even for a hobby coder like me!
Right - just gotta code it now - once more into the breach - thanks fella - amazing help
Welcome, feel free to dm if you need more help
Otherwise, $close
Use the /close command to mark a forum thread as answered