Add control to logical-tree parent - wpf

My Main Window is a relatively simple DockPanel:
<DockPanel>
<!--Bottom row-->
<Border DockPanel.Dock="Bottom">
<DockPanel DockPanel.Dock="Bottom">
<!--Detector Indicator-->
<views:DetectorIndicatorView DataContext="{Binding DetectorViewModel}" DockPanel.Dock="Left"/>
<!--Logo-->
<Image DockPanel.Dock="Right" HorizontalAlignment="Right" Source="/Resources/Images/Logo.png"/>
</DockPanel>
</Border>
<!--Main display-->
<views:TabControlView DataContext="{Binding TabsViewModel}"/>
</DockPanel>
Inside the TabControl's SelectedContent there's a viewmodel for each tab, and each one of those can host a variety of viewmodels.
At one point, the tree basically looks like:
<MainWindow>
<TabControl>
<ExamTab>
<EditExam/>
</ExamTab>
</TabControl>
</MainWindow>
And on the EditExam page, I want a toolbar to appear in the Bottom row of the MainWindow. The toolbar buttons will be bound to commands ont he EditExamViewModel.
Is there a way I can "inject" an inner control like this into the "outer template" (i.e., the main window)?
The only way I can think of is to take the bottom row out of the MainWindow and paste it into each individual view, identical except for the one instance in EditExamView. Is that the only way?

Is there a way I can "inject" an inner control like this into the "outer template" (i.e., the main window)?
No, there is not, at least not in XAML.
You could it programmatically by for example getting a reference to the parent window in the view using the Window.GetWindow method, or by raising an event or send a message from the "tab" view model to the window view model or window using an event aggregator or a messenger.

What you describe is common in modern applications. Even menus are often swapped depending on the active view. However, there is no built-in way of doing this in XAML or WPF. The easiest way to solve this is
[...] to take the bottom row out of the MainWindow and paste it into each individual view, identical except for the one instance in EditExamView. [...]
The hardest way is to develop all that is needed for this scenario yourself including
Creating views and view models as data context dynamically
A concept to define areas where your views should be injected
Swapping in and out dependent views including their view models
Communication between views for synchronization or updating
Managing activation and deactivation of your exam tabs
Custom commands that you can wire accross views to your tab view
...
This is a lot of code that you might not be able to write on your own. But you are not alone, because there are application frameworks intended to bridge the gap between UI frameworks and your code like Caliburn Micro or Prism. These frameworks enable you to skip a lot of boilerplate code and provide services and mechanisms for various issues, but at the cost of learning them and some customization to fit your needs.
Prism as an example provides the following solutions to the issues above
A dependency injection container
Regions that define areas within your application
A rich region navigation service
An event aggregator for communication
Region adapters with active awareness
Composite Commands that can be used across views
...
This looks overwhelming at first, but the more you become familiar with a framework of your choice, the easier application development gets, as you will reuse concepts and components. At this point I recommend you not to re-invent the wheel. At first, you could use the easy solution and start getting familiar with any framework and gradually migrate your application.

So actually I’ve come up with a pretty good and simple solution, which is simply:
<ContentControl Content=“{Binding TabControlViewModel.Tabs[SelectedIndex].CurrentViewModel.ToolbarViewModel}”/>
If the current view model doesn’t have a toolbar view model then it’ll just evaluate to null and show nothing. Then I can define a data template for ToolbarViewModel and we’re all set.
If I wanted to enable various pages to have different things in the bottom bar, I could have ToolbarViewModel be some more general type (and probably a different name), possibly whatever my view model base is, and then any page’s VM could be any type of view model I want, and I could set the DataTemplate. The only caveat would be I don’t think I could have more than one template for any given VM, but I could get around that by creating simple subclasses for each way I’d want it to render so I could have different templates.

Related

Several WPF- / XAML-Files performing better than a big one?

I was talking recently to another GUI developer that was looking at one of my WPF applications. He suggested to break down my very large WPF views (files) into several smaller views. According to him this should promote loading performance as elements that are loaded from UserControls in separate files are rendered only when they actually come into view.
In my main view I currently have over 10k lines of XAML. As the main part of this view is a big TabControl with several large TabItems it would be easy to transfer the content of each TabItem into a separate file. It is true that most of the Tabs will not be used by every user or at least not directly after startup.
However, I was not able to verfy his claim by searching the web. Whenever I search the internet for WPF performance optimization I find all kinds of suggestions, but splitting up large XAML files into smaller ones was never mentioned in any way there.
For me, personally, having one big XAML per view is more comfortable and reusability is really not a problem in my case. So now I am wondering:
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
Would it really make sense to break my large views up into serveral small XAML files for each part that might not be needed at first?
From a maintainability and reusability point of view, yes. But whether you define content of each TabItem inline or in a separate UserControl won't matter from a performance point of view.
So you won't gain any performance benefits of doing this:
<TabItem>
<local:UserControl1 />
</TabItem>
...versus doing this:
<TabItem>
<Grid>
...
</Grid>
</TabItem>
You should consider adopting the MVVM design pattern and bind the ItemsSource property of the TabControl to an IEnumerable property of a view model and use DataTemplates to define the appearance of each item rather than defining everything inline though. Doing this, only the contents of the selected TabItem will be loaded into the visual tree.

What is the right way to approach the TabControl with complex views?

My application is for medical clinics and I select a patient and then there are several Tabs to choose from, Patient Info, Family History and so on. I started out with all tabs in the MainView but have come to the conclusion that each tab needs to be on separate Views because of the complexity of the screens.
How then do I share the Patient info across multiple views? All screens relate to the Patient in some way and I have gone down the road of MainViewModel hosting all the data but that seems like a bad idea because I manipulate data on separate views and need to get the updates back to the MainViewModel. What is the right approach, I have searched the internet for days looking at different architecture and had little to no luck finding any type of similar architecture.
What I did so each ViewModel could access the Patient data is use the code below.
<TabControl Grid.Row="2" x:Name="TC">
<TabItem Header="Patient Info" IsEnabled="{Binding IsPatientSet}" DataContext="{Binding}">
<view:TabPatientView DataContext="{Binding ElementName=TC, Path=DataContext}" />
</TabItem>
<TabItem Header="Clinical Worksheet" IsEnabled="{Binding IsPatientSet}">
I bound each ViewModel to the MainViewModel since each ViewModel was just one aspect of Patient Info. Works great!
The architecture of a program depends on different varibles and there is no one correct answer which I can give you.
However, I can propose some ways to handle your issue:
Keep a Master ViewModel (which is what you are doing now). Create a ViewModel for each View and use a common class (e.g Service) to share patient info between the View models. In this case, service may also expose an event which can be raised when patient info is changed.
Use a light weight WPF infrastructure like MVVM Light Toolkit to share changes in patient info by using the Messenger instance. (Like option 2, but using free 3rd party infrastructure)
Use PRISM with DI.
If all of yours View-ViewModel code resides in the same DLL, you might consider using option 2, or 3.
If some of the View-ViewModel resides in different assemblies you might consider using option 4 which presents the EventAggregator design pattern.
Hope this help to get you on the right path.

Split view into two separate views

I'm building a WPF application which very simplified looks something like this:
I have an ApplicationView which holds the menu and a ContentControl.
The ContentControl binds to the property CurrentViewModel which is set by the menu and rendered by its related View (Views and ViewModels are coupled by DataTemplates defined in the App.xaml).
I found this approach on Rachel Lim's blog
So in this example my View contains a list of duties as well as a "Details" window of the currently selected duty.
This setup works fine, but I think my ViewModels are getting too fat!
The non-simplified version of this ViewModel is up at around 500 lines of code, for handling:
Initializing filters
Logic for filtering list
Displaying duty details
Add/Update/Cancel/Delete logic
Now I'm very new to WPF but that seems like too much code, yea?
And it will be even bigger before I'm finished with it.
Anyways, I was thinking that I could split the ViewModel into two separate ViewModels; one for holding list and filters and one for showing the details. But how is this best accomplished?
I have thought of two approaches, but don't know which is preferable:
Create a DutyMasterView whose sole purpose is to hold two ContentControls for the actual Views (ie DutyListView and DutyDetailView each with their own ViewModel)?
I'm using MVVM Light as my framework so I suppose I could use the messaging service to tell the DutyDetailViewModel which Duty to display, right?
Alternately create a DutyMasterViewModel which exposes the selected duty.
Ditch the DutyMasterView and nest the DutyDetailView in the DutyListView.
Does it make sense to split my ViewModel into two or should I just stick with my fat ViewModel?
If splitting the ViewModel is recommended which of my suggestions makes most sense?
Are there other approaches that I should consider?
If you're still looking for opinion, I'd do it almost like you mentioned in point 1 but you don't need any messaging.
You create two VMs. Let's say DutiesVM and DutyDetailVM. DutyDetailsVM contains just some string properties for ID and Name.
In DutiesVM you create two properties:
ObservableCollection<DutyDetailVM> DutiesList
DutyDetailVM SelectedDuty
Your DutiesView can look like this:
<DockPanel>
<v:DutyDetailV DockPanel.Dock="Right" DataContext="{Binding SelectedDuty}">
<ListBox ItemsSource="{Binding DutiesList}" SelectedItem="{Binding SelectedDuty}"/>
</DockPanel>
Now you can create ListView ItemTemplate that binds to DutyDetailVM Properties.
is usercontrol that defines the DutyDetail view. Selecting the item in the list updates the details control automatically.
That's just the sketch but I think you can get the point from it.

MVVM, The best way to structure the View

I have made a root AppView, a root AppViewModel for my application as a container for all the things. Within the application view, I have a TabControl that each tab has its own task to do. One tab for imoprting data, one tab for issuing, one tab for management and etc:
App_View[Model] // root
{
TabTask1_View[Model], TabTask2_View[Model], TabTask3_View[Model] // tab items
}
1) In MVVM, Is it standard that I have grouped my whole views and view-models into the main application-view and application-model-view ?
2) In MVVM, The model should be implemented for every view & vm ? Or is it standard if I implement the whole models into one or two class files and share the model between them? I personally think that model part is not specific to a certain view, like the class 'student' that can be used anywhere in the code and is not restricted to a certain view. Based on this, if the models are general and shared, yet, is it good to follow the naming convention Class + 'Model' for it? like StudentModel? Is it helpful/necessary to add 'Model' after the general or shared class name like the thing I said?
3) In WPF, What is the best way to implement the Views? I want to edit and design very easily and without any restriction, and it should be standard enough to cover future needs. There are 4 things to use: Window, Page, UserControl and DataTemplate. Which one is the best option that you go for? UserControl or Page?
4) In WPF, How can I load the UserControl/Page(View) inside a tabItem dynamically at run-time based on the MVVM approach?
You're cheating. That's 4 questions!
1)
In terms of how you group your Views and Viewmodels I've seen people put views and viewmodels in the same namespace/folder and others separate them out into different folders based on functionality. The best option for you is what suits you/your team. There is no "right" way.
2)
Keep it DRY - so don't repeat yourself. It is perfectly sensible to reuse code. If you have common classes keep them common. As for naming, the name of the class should be helpful in explaining what it does: I'm sure you'd be able to figure out what the classes NavigationService, NavigationMenuItem and NavigationMenuView did and probably could put together a good mental model of how they relate. So - if naming a class BlahViewModel or BlahModel is useful to you, do it.
3) Implementing views:
A Window is always shown independently. Pages are intended for use in Navigation applications (usually with Back and Forward buttons, e.g. Internet Explorer). Pages must be hosted in a NavigationWindow or a Frame. If you're looking at dynamically adding/removing content, adding content to ItemsControls (TabControl, etc) then you'll want to be creating user controls. You can put user controls in Page and Window object, into other controls, etc, and are really the workhorse for WPF developers.
4)
You have a number of options here:
1)The quick and dirty way is to create DataTemplate which, on being given a ViewModel of type X, load up and apply the ViewModel to their data context. This will allow you to inject a ViewModel directly into a control and have the correct View render.
An example:
View.xaml
<ContentControl Content="{Binding Error, Mode=OneWay}" />
ViewModel:
private void ReceiveError(ErrorViewModel errorModel)
{
//if (errorModel.AcceptCommand==null || errorModel.AcceptCommand is NoOpCommand)
errorModel.AcceptCommand = new DelegateCommand(ClearError);
Error = errorModel;
}
public ErrorViewModel Error
{
get { return _error; }
set
{
_error = value;
_propertyChangedHelper.NotifyPropertyChanged(this, () => Error);
}
}
Styles.Xaml (ResourceDictionary)
<DataTemplate DataType="{x:Type vm:ErrorViewModel}">
<DataTemplate.Resources>
<conv:CustomisableBooleanToVisibilityConverter x:Key="VisibilityConverter" TrueValue="Visible" FalseValue="Collapsed" />
</DataTemplate.Resources>
<Popup AllowsTransparency="True" PopupAnimation="Fade" Placement="Center" StaysOpen="True"
PlacementTarget="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:ModuleView}}}"
IsOpen="True" Width="400" SnapsToDevicePixels="True"/>
So you can see I'm injecting my viewmodel directly into the content control and it's using the data template that is bound to the viewmodel's type to find a View for it.
2)
A better bet is to use a DataTemplateSelector. This basically allows you to specify which templates are available for a control and then uses logic you code to determine which datatemplate to use. You can find an example of this here.
3)
Use a framework that abstracts the UI controls away. Microsoft has a framework (free) that does this called Prism. Basically, instead of adding your usercontrols directly to a TabControl,ItemsControl, etc you add your control to a named "Region". This region is mapped to an underlying control and an adaptor is put in place to manage how that UserContorl is added/removed when you ask it to be. You can find an in-depth discussion of this here. Beware, though, Prism is an application framework so implementing this isn't 3 hours work.
Here is not an answer, it's my experience that i'll explain to you and how I handle with MVVM. I started with WPF 3 month ago and I handle with it.
For each new theme/menue/option I create a new project file wich contains the ViewModels and the Views. All Business classes are collected in one Project file because I may have to use it in more than one ViewModel.
Yes, it was helpful for me as beginner to name the the classes ...ViewModel and ..View. It maked it easy for me to separate the diffrences and also it was/is easier to explain other people your classes ( for example if u have a problem with your coding )
I am using UserControls for our different views and I load them into ContentControls and TabControls without any problems.
Have a look at Prism for MVVM-pattern.
Point 1:
It depends. There are two widely used approaches AFAIK. First is as you've said group all VM's that constitute the same Window with direct dependencies to form a class structure that shows your actual program structure. Second is where you use an EventAggregator(Prism) / Messenger(MVVM Light) to loosely link the VM's instead of direct dependency.
Now both approaches have their benefit's
With the first one It's pretty easy to identify your program structure cos your VM dependencies show it clearly, which is not so clearly visible from the second approach.
Second approach helps you a lot when unit testing VM's cos you are not forced to either mock / work-around all the dependent VM's, It also helps code re-factoring a bit when changing project structure(think of "Plug in" classes)
oh and these ^^ are by no means exclusive. You can mix these together well and fine.
Point 2:
Models do not have any recommended 1 <-> 1 relation with a View / VM like what Views have with VM. Models just hold your Business Logic. I've had apps that sometimes do not hold a Model at all. Something there is just 1 Model used by the entire Application(when the back-end is say a c++ library and you just interface with it with a C++/CLI Module). yes maintain the naming convention to append Model class names with "Model"
Point 3
How about all of them? use them where applicable. Do not take a partial preference to any. When a View composes multiple other sections that are by themselves a View with VM I'd have a DataTemplate with the Data a UserControl. Your app almost always uses a Window and Page is useful for navigation based apps I think. Think Page's are what I've used least tbh.
Point 4
This is a question of tutorial's. Take a bunch of examples, see how it's implemented, reason it and pick your approach. If your using VS2010 get MVVM In the box (It's great. no 2 ways about that. Really hope this could get to be updated for VS2012 if it's not already). For VS2012 check out Two Views MVVM CodeProject which shows the concept, you can then apply it to any ItemsControl of your choosing.
Finally atleast when you're starting up, PLEASE start off with using a MVVM helper library. I prefer MVVM Light <- that link has a couple videos by the author of the library showing some usages and you can find extensive help here on SO about it. If you want to do things yourself, learn the basics from it and then implement it yourself. if you take the high road from day-one it's just a much longer learning curve(Just my opinion)

Multiple "sibling" controls, one-at-a-time visible, MVVM

I've got what I think is a fairly simple problem in Silverlight, and I'd like to solve it using MVVM principles, largely as a way of enhancing my own understanding.
Let's say I have a simple LOB app that's designed to let me load up and edit a single Employee (just an example, for the sake of explanation). In my example, Employee is made up of a number of complex objects - an Employee has a ContactInfo, a Skillset, an EmploymentHistory, an AwardsEarned, etc. The idea is that I can have this app load up a single employee and get access to a number of different editor screens. Each component of an Employee has its own editor screen.
Visually, the app just ha a left-hand nav bar and a main view on the right side. The nav bar just lets me type in an employee number and load it into memory as the "active" employee. It has a simple list of links - clicking a link should load the appropriate editor screen on the right side.
There are a couple concepts that I don't think I understand well enough, and I'm having trouble proceeding. I know there's always more than one way to skin a cat, especially when it comes to WPF/Silverlight/XAML/MVVM, but I'm having trouble thinking through all the different concepts and their repurcussions.
View-First or ViewModel First
After much thinking about MVVM, what seems most natural to me is the concept of viewmodel composition that Josh Smith seems to promote in his often-quoted article. It seems like the idea here is that you literally model your UI by composing viewmodels together, and then you let the viewmodels render themselves via typed DataTemplates. This feels like a very good separation of concerns to me, and it also makes viewmodel communication very direct and easy to understand.
Of course, Silverlight doesn't have the DataType property on DataTemplates, to many complaints: one, two. Regardless, what I see promoted much more often than viewmodel composition is a more view-first design, where the viewmodel for the view is typically instantiated in the view's XAML or via a DI container, meaning that you can't hand it any parameters. I'm having a really hard time understanding this: how is a ViewModel supposed to serve a Model to a View if I never get to tell it what data is in the model? Reaching through a view to get to its viewmodel doesn't seem to make sense either. I'm very hazy in this area but it seems the accepted answer "use a mediator/lightweight messaging framework." I'm just going through some tutorials now on the messaging system in MVVMLight and I'll be looking at similar stuff, if for nothing else than simply to understand the concepts, but if anyone can shed some light on this I'd very much appreciate it. Anything involving Unity/Prism or MEF is valid, but I haven't gotten that far in my quest for knowledge yet :-)
Instantiating Views and Selecting Them
Theoretically (I say that because SL doesn't support DataTemplate DataType), the viewmodel composition approach could make this very simple. I could have the right side of the screen be a content control whose Content property is bound to a property called ActiveEditor. A parameterized command for the hyperlinks would set ActiveEditor to a given viewmodel.
With a more view-first approach, how would I proceed with this? The first thing that comes to mind is instantiating all of the controls in the XAML of the main view.
Is manipulating the Content property of a ContentControl a good way to go for this kind of situation, or am I better off doing something like setting visibility on each individual control?
The ViewModel (VM) is written so that it is 'wired up' to the Model but has no knowledge at all of the View - in fact, this is what makes it very good to unit test (see NUnit) as it has no idea, and less does it care, whether it is being used by a UI or a Test Framework.
The VM exposes public CLR properties which implement the ICommand interface, the View, having instantiated a VM using (generally speaking anyway) its default constructor, then binds its Buttons/Hyperlinks etc to these Command properties like. So, for example, you may have a VM that exposes a CloseCommand to exit the app, the View may contain a MenuItem that binds to that command, such as:
<MenuItem Header="E_xit" Command="{Binding Path=CloseCommand}" />
Now, the VM would also expose a public ObservableCollection of objects that you want to display in your UI. Whether you populate this ObservableCollection as part of the VM constructor, or whether you do it via a UI interaction (say another Command assigned to a Button click) is up to you but the end result is that you bind a View control to this exposed ObservableCollection in XAML like:
<y:DataGrid ItemsSource="{Binding Breakdown}"/>
or equivelant for whatever control you are using to display the data (not sure off the top of my head what elements a DataGrid has in Silverlight as opposed to WPF).
Meanwhile...: The Mediator pattern is used for VM's to interact with each other, not for the View to interact with the VM. For example, you might have a custom TreeView that has its own VM on the same View as the main chart screen. In this case you could use a Mediator for the TreeView's VM to communicate with the Charts VM.
As for the last bit of your question, I think set up a basic framework using Josh Smith way in the article you mentioned and use that method to add additional ViewModels to the right hand side of your silverlight app.
Hope that helps a bit at least.

Resources