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

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.

Related

Add control to logical-tree parent

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.

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)

Should complex silverlight pages be split into controls even if they won't be reused

Background
I'm working on a silverlight page that has grown quite complex. Its 650 lines, contains It has four grid views, a tab control, etc. Also note we're following the MVVM pattern. This is silverlight 5, if that matters.
The page seems suitable to be split into a main page with four controls. I doubt the controls would ever be reused in other pages.
One benefit is that with all of the indenting, it is a bit awkward to work with the xaml. Second benefit is my belief that it would be easier to follow/understand if the controls were split apart.
Questions
If I split the xaml into seperate controls, should I also split up the ViewModel? For the same reasons, it would make the view model less complex and easier to understand in the context of just the control it works with.
Are there any potential problems with splitting the controls? Perhaps binding issue if for some reason a checkbox on one control should affect the behavior of a different control? But this might be solved by having the various view models have a reference to each other?
I would say that yes you should split the page up into seperate controls and yes you should split up the viewmodel if the cost of doing so will be less than the cost of the maintenance difficulty created by the current model.
Most of the challenges that this presents can be addressed by having a main viewmodel that contains references to all of the child viewmodels and manages the relationships between them.

Caching of UserControl objects

I have a WPF application where I show and hide lots of UserControl objects. The XAML code looks something like this:
<ItemsControl ItemsSource="{Binding Path=MyListOfStuff}" >
<Controls:MyControl Stuff="{Binding}"/>
</ItemsControl>
Creating those objects takes a lot of time. Profiling shows that 'InitializeComponent' takes a significant amount of time for the MyControl objects. I want to pre create these objects to reduce that time. How can I do that? I still need the xaml code and don't want to replace all of it with just code.
It's not possible to use virtualization because the items in the list are sometimes bigger than the view, so CanContentScroll must be False.
There are two aspects to solve your problem. even you can use both of them..
UI Virtualization
Data Virtualization
You should have a look at
http://blogs.microsoft.co.il/blogs/tomershamam/archive/2009/10/01/ui-virtualization-vs-data-virtualization-part-2.aspx
also if you are using .net 4.0 you can use Lazy class to support Data Virtualization easily otherwise you will have to create some classes to support that.
Regards.
It is possible to do UI caching in WPF, but I'm quite sure it is not what you are looking for.
Bitmap caching is useful when one visual is painted more than once, so it is rendered only once and for subsequent renderings only copied from the cache.
You will have to have a look at virtualization (see Shoaib's answer).
Article about bitmap caching.

WPF: Buidling my own paging itemlist....;)?

for reasons based on storabiligty I have the following objects in a XAML graph:
A WorkArea,
Containing WorkSheets,
Containing WorkItems
WorkArea, workSheets are ItemsControl instances.
To start: The reason that I am not using standard elements here is that mine are going to get loaded / saved - they represent a business contect (actually the work area of a trading application), and I want those to have as few "surplus" elements as I can. I especially do not want to be tied into user level controls that are from a third party and regularly changing dll names (during upgrades - the major version is encoded there) and I am not sure I will not replace them at all, so I rather go with my own "slim" objects.
The WorkArea corresponds to a window (actually there is a WorkAreaWindow that will take the WorkArea as ContentItem.
The WorkSheets are supposed to work like a TabControl - you can switch between them.
How do I do that? ;)
I get the impression that with the templating mechanisms I could possibly "visuall wrap" the WorkSheets as pages in a TabControl, but I am pretty much totally lost on the how. Anyone can enlighten me?
Here is how far I got:
My Herarchy is WorkArea -> WorkSheet(s) -> WorkItem(s)
WorkArea should be presented as a TabControl, with one tab per WorkSheet.
WorkArea:
<local:WorkArea x:Name="WorkArea">
<local:WorkArea.Template>
<ControlTemplate>
<TabControl>
<ItemsPresenter />
</TabControl>
</ControlTemplate>
</local:WorkArea.Template>
<local:WorkArea.ItemTemplate>
<DataTemplate>
<TabItem Header="{Binding Path=Title}">
<ContentPresenter />
</TabItem>
</DataTemplate>
</local:WorkArea.ItemTemplate>
<local:WorkSheet Title="Markets">
<local:WorkTile local:WorkSheet.Row="2" local:WorkSheet.Column="3">
test-11
What I can see now is a TabControl, with one Tab. No text, all content in the one tab. Anyone an idea how to split this further?
You should carefully read Josh Smith's introduction to MVVM here and look at the demo application source code. The demo application is almost exactly what you are asking for. It generates a tabbed interface dynamically based on custom classes for "contacts" data using data templates, observable collection binding and tabcontrol/tabitem. Some of the MVVM and commanding stuff might not be your thing, but a portion of the code does what you are looking for. The XAML has no code behind at all. You would simply set that data context of your window to your work area class instance that would have an observable collection of worksheets which in turn have an observable collection of workItems and item/data templates will do everything.

Resources