Dynamically create tab and inject a view in it - c#

I use AvalonDock to have a vs-like docking style, and I use prism to inject views in my application.
Basically the user will have a panel on the side with one button per view loadable, and each time he presses one, I want to create a new tab on my AvalonDock's DocumentPane, and inject the right view in it.
Now I was under the impression that prism is good for this kind of scenario, but I can'f figure it out.
Also, I stumbled accross DocumentPane and DockablePane region adapters by Markus Raufer, have added it to my project and registered the mappings in the bootstrapper.
This allows me to compile the solution (so I'm guessing I'm getting close).
So far, I do this:
In my Shell I have a place with:
<avadock:DocumentPane avadock:ResizingPanel.ResizeWidth="500" Background="Transparent"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainTabControlRegion}">
</avadock:DocumentPane>
In my code-behind, after Bootstrapping etc, I have a place that does:
m_RegionManager.Regions[RegionNames.MainTabControlRegion].Add(oneOfMyUserControls);
Executing this line doesn't show anything more to the user, but if i execute it twice, it will make an error saying a view is already registered (so it did add something!).
Furthermore, when i put a regular ContentControl, mark it with prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainTabControlRegion} then add a UserControl in it the very same way I add it to AvalonDock's DocumentPane, it works. freaky
What am I doing wrong?
Thanks,
bab.
EDIT:
If define the MainTabControlRegion like this, the first view actually gets added, now id i add another one (different UserControl) it doesn't show it, but WPF Inspector says it's there.
From my point of view, it is indeed adding UserControls to a region, but it doesn't know how to create a new tab for each UserControl I add to the DocumentPane.
Since I'm not specifying anything about that, I'm probably missing a piece of code?
<avadock:DocumentPane avadock:ResizingPanel.ResizeWidth="500" Background="Transparent">
<avadock:DocumentContent Title="" prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainTabControlRegion}">
</avadock:DocumentContent>
</avadock:DocumentPane>
I want it to create a new tab each time i add a usercontrol and insert it in there.
EDIT 2: Solution --> Here

This problem can be caused for many reasons.
Or the RegionAdapter is not well suited for the user controls you are trying to add, therefore I would recommend you to have a look at RegionAdapter implementation so you can have a good understanding of how it adapts your view in the region and customize it to fit your needs.
Or the user control you are adding has a particular behavior and is bugging the RegionAdapter when it tries to add your view to the DocumentPane items. Therefore you can customize the RegionAdapter or fix the user control behavior.
Or it is simply a data binding problem. The fact that nothing shows up on first execution is kind of strange. Try to inspect your DocumentPane property Binding with WPF Inspector. It saved my life more than once when dealing with custom RegionAdapters.

Related

Workaround for screen flicker

Writing a fairly simple app with c#/wpf.
When opening a second window there is a brief flicker or flash.
Extensive googling says that this caused by screen repainting, so not much I can do about that.
(I haven't included any code because it seems this problem is well known and something most people 'learn to live with')
So, I thought, why not put all the XAML in one file with each page within its own grid that I can hide/show with visibility.visible or visibility.collapsed etc.
Works nicely (apart from a very slight delay - less than 1/2 second - the first time i show the second window grid), but I'm unhappy at the idea of containing all the code behind in a single page. (for what its worth, i'm told that compiler see's it all as one file anyway but ... )
Is there a way I can create separate 'code behind files for each 'windows' (in reality a XAML Grid) functionality whilst linking them all to the same Xaml File?
(I have a horrible feeling having typed this that the answer is obvious and I should already know it ...)
Thanx
If I understand you correctly, you just need to create a new Control Class-Code Behind pair for each 'window grid'. This is done in VS by clicking Add-Create Element-User Control (of name UserControl1.xaml, rename it to something Like YourControl.xaml) in Solution Explorer (I think you already know all this, but just in case).
Now, if there is no specific requirement for the control to be of type Grid, you can use it as it is:
<MainWindow>
<Grid>
<YourControlNumberOne />
<YourControlNumberTwo />
<YourControlNumberThree />
<Grid/>
</MainWindow>
If you specifically need Grid-based control, just change the base class of YourControl to Grid, and change the topmost XAML element in the associated XAML file to Grid.

Why do we need UserControl ? It seams that a Custom Control can do all the things that UserControl can do. WPF & Windows Store App [duplicate]

I've been reading some explanations about the difference between User and Custom Controls, for example this:
http://www.wpftutorial.net/CustomVsUserControl.html
I want to create, for example, a simple composition of a datagrid with 2 comboboxes which are responsible to change the values from the datagrid's items. I want to create a specific control for this because I'm going to use it a lot of times. I would like to implement the logic behind and then in the xaml invocation I only have to specify the itemsSource.
For this example should I create a User or Custom control? Since I will have properties and logic, should I have a viewmodel for this control?
EDIT: Do you know some articles with clear conceptual separation between these 2 options?
Choice is not only between user control and custom control, but among user control, custom control, customizing control template, customizing data template, header template (for collection based controls), attached properties.
Refer to Control Authoring overview
I go by following order of consideration
Attached Properties : If functionality can be achieved, I use attached properties. Example, Numeric text box.
Control Template : When requirement can be fulfilled by customizing the control template, I use this. Example, circular progress bar.
Custom control: If control template cannot do it, I use custom control. Provided I need to customize/extend already present control. Example providing Sorting, Filtering based on header row in GridView (GridView is present in metro apps, used just to illustrate the example)
User control: Least preferred one. Only when composition is required, and I am unable to do it using custom control. Like in your example, 2 Combobox, and 1 datagrid. User controls does not provide seamless lookless feature that can be leveraged through custom control or control template.
You already have some great answers that explain the differences but also understand that custom controls and UserControls have different purposes:
A UserControl typically encapusulates some sort of composite behaviour. If you have an application that needs to edit contact details in many places, for example, you could create a custom control that has the labels and text fields for all the data laid out with a submit button that has the relevant code and reuse this control throughout your application.
A custom control is a control that is derived from one of the WPF control classes (E.G. Control, ContentControl etc.) and has to be created in code.
These control usually have a single cohesive purpose (think TextBox, ComboBox, Label) rather than acting together as a whole (although this doesn't have to be the case).
UserControl's are usually easier for people unfamiliar with WPF as they can be visually designed.
My suggestion would be to start off with a UserControl. You can always refactor this into a custom control at a later date as you become more familiar with the way WPF works. Creating your control as a custom control will require knowledge of ControlTemplates and Styles as you will need to provide your own to define a look and feel for your control.
When all is said and done, as long as the control behaves correctly, it doesn't matter which approach you use.
See this post for an example of two approaches to the same problem. The post author wanted a control which can present modal content in front of the primary content. The post author actually answered his own question by implementing it as a UserControl. I have added an answer to the post which creates the control as a custom control but both have the same end effect.
If you have a view-model and you wish to create a view for it use the User-Control.
If you need an autonomous control that has no specific view-model,
you probably need a custom-control.
If you find that the functionality you need as whole, already exist in other controls you need to override an existing control template.
(i.e: for a diamond shaped button - you need to override the button control template.)
Regarding attached-properties and attached-behaviors, those are useful when you have a control which you want to extend with more properties or you want it to behave slightly different than its default behavior.
In the provided case of the composition the OP described, it can be achieved with either user control or custom control. I would prefer a custom control since there is no specific view model provided, the "input" is only a property bound to an item collection.
Oh, and, I am sorry for slightly being late.
The best explanation is in the msdn. CustomControl is more a "virtual" name, there is no class called "CustomControl" in WPF, instead its meant creating a new class building on top of one of WPF control classes, like Control, ItemsControl and even more specific Controls like TextBox or Button.
For your specific case, a UserControl should be enough, creating a CustomControl is something that can easily be avoided. While its not a bad thing, a lot of people, especially beginners in WPF coming from WinForms tend to subclass more then necessary.
If this is somehow your first time building controls, I recommend UserControl as VS lets you design its interface more easily. Custom Controls are more powerful, but you have to CLEARLY separate your control's logic from its interface and this requires a bit more preparation.
You can easily Visually design CustomControl.
Create new UserControl (or Window). Create its xaml structure visually in Designer. Copy-paste body of the resulting xaml inside ControlTemplate of your new CustomControl (Eg. in generic theme file).
If I remember right, you are also able to visually design CustomControl template directly, in Blend.
Of course you can also instance the wip CustomControl in a Window and put the Window's Designer view as new panel above the control's xaml view in VisualStudio.
Some xaml bindings from style template don't show in Designer like this though, until I rebuild.
[ Imho GUI is mainly a visual matter and should not, and doesn't need to, be created in code. ]
Well to create a Custom control you need to implement it as a User control. Your own User control is called a Custom control. It is pretty simple.
UserControl is the base class for containing your custom content :
<UserControl>
Your custom WPF content
</UserControl>
I don't totally agree with the article. However in your case you need a UserControl that you can re-use latter in your UI.

Open new View when new ViewModel is available?

I am relatively new to WPF/MVVM. Our current WPF project is still a prototype application, which means we haven't come to designing of main layout. But we do have designed some reports (by reports, I mean some quite complicated UserControl each of which has some configuration controls such as ComobBoxor TextBox, and some DataGrid, Graph controls for the data we want to present) as Viewand their ViewModel. It is still prototype, so we just need to open a new Window which displays any of these UserControl. In the future, we might change it to locate different UserControl in different regions inside the main window, like the layout of Visual Studio. The MAIN point is, our application would include almost a hundred of such UserControl or what we call reports. So it is different from my previous working projects which had static layout/MainView.
I still haven't figured out a good architecture for it. Our classic usage scenario is to let the user to select in the menu report to open, and so we have Command (either in MainViewModel, or in any ViewModel of report) objects to open a new report. So basically the Command is generating a new ViewModel (ViewModel first case) and then a corresponding View should be generated (by whom?), and finally a new Window should be opened including the newly-generated UserControl.
I guess I need two services:
a service which subscribes to the new-ViewModel-generated event, and resolve the UserControl when such event happens.
(for our current prototype application) a window manager, which subscribes to the new-UserControl-generated event published by the 1) service, and then opens a new Window to display it.
And in the future for our actual application, we can change the 2) service and put them into different regions. For the second, it is simple and only temporary, I can just have one object in the code-behind of MainView, which subscribes to the event using EventAggregator, and generate a new Window. Is it correct ?
Can somebody tell me how I should achieve this?
Data binding can already handle this for you. In the container where you want to display the reports add a ContentControl and bind it to a property that holds the VM for the report that you want to display currently.
<Window>
<ContentControl Content="{Binding Path=CurrentReport}" />
</Window>
To display the different reports wrap each of the UserControls in its own DataTemplate that can be injected into the ContentControl. To actually resolve the view you have a few choices. You can create a DataTemplateSelector to map them or just specify the VM types on your templates. In either case, make sure the templates are in scope at the ContentControl (in Resources in the same file or a parent, or merged from standalone ResourceDictionary).
<DataTemplate DataType="{x:Type viewModels:FirstReportViewModel}">
<views:FirstReportViewControl/>
</DataTemplate>
John Bowen beat me to it, by I thought I'd still post, maybe it helps.
For associating views with view models you can use data templates in a resource dictionary.
<DataTemplate DataType="{x:Type vm:AllCustomersViewModel}">
<vw:AllCustomersView />
</DataTemplate>
As you probably already know, you can set namespaces within your resource dictionaries. In this example vw and vm reference the folders containing viewmodels and views respectively.
Now you can use content control to generate the views by binding to the view model.
<ContentControl Content="{Binding SomeViewModel}" />
The code above has been shamelessly stolen from Josh Smith btw.
So, you should not need a service for resolving the association of view to viewmodel. Let the framework do the work for you.
I actually do not recommend opening new windows. If you must, using a "Window Controller"-Service of some sort will be unavoidable. However, I advise you to stick to a single window containing multiple viewmodels and exchanging them upon receiving certain events.

Dynamically generating controls in WPF using Prism, MVVM, MEF

I am using WPF with Prism and MEF for my application. There was a need to create controls dynamically. And so here is my problem!!
As far as I know I should not be having code in my code behind (SomeFile.xaml.cs) to keep my code easily testable. And so the code should be actually moved to ViewModel.
But my code generates UI controls dynamically. And I dont think that the ViewModel should know anything about the Controls.
So where and how should I go about writing this code?? What would be the right approach?
Hope I made myself clear!
Thanks
When working with WPF/MVVM, your data layer is your application (the DataContext), and you use things like Templates to tell WPF how to draw your application components to the UI.
For example, suppose you're given the task to dynamically render a bunch of controls.
The WinForms way might have been to loop through your objects, create a UI control for each object, then add the UI control to the screen.
However with WPF/MVVM, you would instead create a class representing each object (a Model), and give WPF a list of those classes to display.
There are many different controls WPF can use to draw a list of objects, but the most basic of them is probably an ItemsControl. I have some examples of a simple ItemsControl on my blog if you're interested.
Now even though you've given WPF the list of your objects to render, and told it what control to use to render the list, it still probably doesn't know how to draw your object. The usual solution for this is to include an XAML template of some kind to tell it how to draw your object.
Here's a simple example template that is used to tell WPF how to draw an object of type MyClassObject:
<DataTemplate DataType="{x:Type local:MyClassObject}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
I hope that helps get you going in the right direction :)
From my perspective, the view has the responsibility to render the data/model provided by the viewmodel. While it is ideal to keep as much of the model->view translation logic in the viewmodel, creation of controls adds significant complexity to move to the viewmodel, because of the coupling or infrastructure that it could add.
While you could:
1) Give the viewmodel direct access to the view, allowing it to create controls directly
This adds coupling...
2) Create an interface on the view to manipulate controls
This means the view must be passed (not simply bound) to the viewmodel
3) Create an abstraction of controls to bind to the view, and have the view render based on the abstraction created by the viewmodel
This adds a maintenance nightmare as your control set expands.
I suggest exposing the model (either directly or wrapped in micro-viewmodels) via a property on the main viewmodel, and binding that to a property on the view via xaml, such that any PropertyChanged on the viewmodel will send an update to the view. Use the model information and your control creation logic inside the view to clear and re-create the controls and bind the model dynamically to the controls you create. This will simplify both the creation and binding of the controls, and you won't have to practice any voodoo to get information entered into the controls back into your model.
Note that even if you created an intermediary class (an attached behavior, adorner, or something else), it will still need to be able to access the view's control structure directly to attach the generated controls to the visual tree, which may cause other problems.

One event for several forms

I am currently faced with a trivial task but I can't think of a solution.
In order to explain the theory of how it should work ...
There is a form of authentication. http://prntscr.com/pwat5
This form fits on TabControl -> TabItem and TabControl in turn is placed on the component Grid.
Actually, on that key input is an event by clicking authenticate and change the login form to another form.
Such forms of authentication, I need more, I went for it in the following way and laid the form data to a specific component, the structure looks like this:
Grid
ListBoxItem
MyAuthForm
... //Well, actually imposed on the rest of the crap form MyAuthForm
For an identical copy of my form MyAuthForm I clone the object, and to be more precise, I clone ListBoxItem together with all its contents to the new object and thus add it to the component Grid, that is, get a new cloned object.
Grid
ListBoxItem
MyAuthForm
... //Well, actually imposed on the rest of the crap form
ListBoxItemСlone
MyAuthFormСlone
... //And so on
But the problem is that my original object carries a variety of events but the cloned object can not deliver on certain events in the original.
How is it possible to solve this problem? To clone an object somehow could refer to the events of the original object?
In general, explained as best I could, I hope most accessible outlined what I want, thank you very much for any hints and ideas, the second day I suffer with this case and so far no ideas.
ps In the manual for each cloned object, I can not create events for such forms of authentication can be more than enough, everything has to be fast, so the only option is to somehow refer to already existing events, wpf allowed for that possibility?
Perhaps since you are working with WPF, if you bind the events to commands or any other mechanism then the cloned window, given the same datacontext would target the same methods and your problem would be solved.
I hope i understood correctly.
In the past i used Caliburn with WPF and there was something called ActionMessage there that might be of use to you.
It bubbles up through datacontexts until it finds a method with the specified name or else it throws an exception. Maybe you can use this, coupled with the fact that the 2 clones share the datacontext instance to enable you to make them all point to the same authentication method.
Hope i got it right.

Categories