WPF - Prism : Show regions in dialog window - c#

I have Dialog Window with a TabControl which contains 4 tabs, each tab contains a region.
DialogWindowTestView.xaml
<TabControl DockPanel.Dock="Top" TabStripPlacement="Left">
<TabItem Header="General">
<ContentControl regions:RegionManager.RegionName="GeneralRegion" />
</TabItem>
<TabItem Header="Materials">
<ContentControl regions:RegionManager.RegionName="MaterialsRegion" />
</TabItem>
<TabItem Header="Design">
<ContentControl regions:RegionManager.RegionName="DesignRegion" />
</TabItem>
<TabItem Header="Units">
<ContentControl regions:RegionManager.RegionName="UnitsRegion" />
</TabItem>
</TabControl>
I've tried two methods in order to display the regions inside the tabs.
First I used RegisterViewWithRegion. this shows the regions correctly, but the view gets called once when first open the dialog window, and after closing the window and re-opening it, the view constructor gets called many times each time the user opens the dialog window.
Edit: It's the view inside the tabItem that gets called many times, not the dialog window.
DialogWindowTestViewModel.cs
if (!regionManager.Regions.ContainsRegionWithName("GeneralRegion")) {
regionManager.RegisterViewWithRegion("GeneralRegion", typeof(GeneralView));
}
if (!regionManager.Regions.ContainsRegionWithName("MaterialsRegion")) {
regionManager.RegisterViewWithRegion("MaterialsRegion", typeof(MaterialsView));
}
if (!regionManager.Regions.ContainsRegionWithName("DesignRegion")) {
regionManager.RegisterViewWithRegion("DesignRegion", typeof(DesignView));
}
if (!regionManager.Regions.ContainsRegionWithName("UnitsRegion")) {
regionManager.RegisterViewWithRegion("UnitsRegion", typeof(UnitSetView));
}
The second method is regionManager.RequestNavigate, this shows the regions correctly, but after closing and re-opining the view all regions disappear. the window will be with all the tabs empty.
DialogWindowTestView.xaml.cs
RegionManager.SetRegionManager(this, regionManager);
RegionManager.UpdateRegions();
DialogWindowTestViewModel.cs
container.RegisterType<object, GeneralView>(typeof(GeneralView).FullName);
regionManager.RequestNavigate("GeneralRegion", typeof(GeneralView).FullName);
container.RegisterType<object, MaterialsView>(typeof(MaterialsView).FullName);
regionManager.RequestNavigate("MaterialsRegion", typeof(MaterialsView).FullName);
container.RegisterType<object, DesignView>(typeof(DesignView).FullName);
regionManager.RequestNavigate("DesignRegion", typeof(DesignView).FullName);
container.RegisterType<object, UnitSetView>(typeof(UnitSetView).FullName);
regionManager.RequestNavigate("UnitsRegion", typeof(UnitSetView).FullName);
What is the best way in order to show the regions correctly without any unwanted behaviors?

Your first approach: RegisterViewWithRegion is a global registration that will live for the lifetime of the application. To make the registration, you need not check for region existence. You should not register multiple times, that will result in behavior you observing.
Move registration out of the view constructor so that they are made only once.
Remove the check for region existence.
Your check for region existence fails and registrations are performed multiple times because when the view is closed it is removed from visual tree and a special region behavior removes the regions from region manager.

Related

Using Tabcontrol in MVVM pattern in WPF

I have multiple window files and i want to merge my Xaml files(window) into a Tab control in a MVVM Pattern.
Each item Tab will represents a Xaml file.
i need something like this:
<TabControl >
<TabItem>
<local:FirstView></local:FirstView>
</TabItem>
<TabItem>
<local:SecondView></local:SecondView>
</TabItem>
</TabControl>
but i get this Error:
"Window must be the root of the tree. Cannot add Window as a child of Visual."
I have seen many topics like this but they use user control or they use a single view with multiple View Model.
Is there any way to import window(xaml) into tab control?
And another important thing, i want to have a button like Cancel, Pushing Cancel means we have to go back one level(go to another tab Item).
view model is not aware of view, so how can i navigate through them?
Is there any way to import window(xaml) into tab control?
No, there isn't. A System.Windows.Window cannot be a child of another System.Windows.Window.
The contents of the tab items should be defined as UserControls.
You should just be able to move the contents of your windows to the user controls.

How can I explicitly load XAML before it's visible?

I have a TabControl with several tabs. The first and main one is very simple one and takes virtually no time at all to load. The second one on the other hand is a representation of hundreds of complex objects, and takes about 1-3 seconds. The application fires up rapidly, but as soon as you click on the second tab, the application freezes for a short while, loading the Tab Control.
This is a quick illustration of the XAML code:
<Window x:Class="MyProgramme.MyMainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TabControl VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0">
<TabItem Header="Simple View" >
<!-- Main view. Loads instantly. -->
<ContentPresenter x:Name="m_simple"/>
</TabItem>
<TabItem Header="Heavy View" >
<!-- Takes about 1-3 seconds to load-->
<ContentPresenter x:Name="m_heavy"/>
</TabItem>
</TabControl>
</Grid>
</Window>
Obviously, this waiting is not very user friendly, and I would like a way to explicitly load the second tab whenever it's convenient, which will be either at start-up, or whenever the UI thread is not too busy and can take the load. Is there a way of loading this tab without stalling the user's work flow?
If you are loading the data for the tab in the constructor, that would be the reason for the freeze.
Rather use the Window's Loaded event instead and if possible, try kick off the heavy load in a background thread. Loaded is triggered once the UI is drawn leading to a better user experience as the UI itself does not appear to freeze.
You should also consider a BusyIndicator or ProgressBar for the second tab while the background load is running to indicate to the user that a long running process is happening.

call to page inside tab control via code

I heed to create wizard and in the wizard I have tab control which have to call to the user control according to the context,I need to create the wizard which will able to invoke
different pages according to the user selection ,currently I call to the pages as follows which I think is not the right way,any Idea how should I do it via code (not in the xaml )i.e. according to some decision invoke the suitable page to the tab control.
this is the xaml:
<Border Grid.Column="1" Name="MainBorder">
<TabControl x:Name="MainTabControl" Height="638" VerticalAlignment="Bottom">
<TabItem Visibility="Collapsed" >
<Frame Source="page1.xaml" />
</TabItem>
<TabItem Visibility="Collapsed" >
<Frame Source="page2.xaml"/>
</TabItem>
<TabItem Visibility="Collapsed" Header="Step 3">
<TextBlock Text="Page 3"/>
</TabItem>
<TabItem Visibility="Collapsed" Header="Step 4">
<TextBlock Text="Page 4"/>
</TabItem>
</TabControl>
</Border>
UPDATE
I was tried in the main window like the following without success
create new tab by code and add to it the page 1 and then add it to the MainTabControl
TabControl tabControl = new TabControl(new Page1());
MainTabControl.add..
.
there is no add in the main tab control
For this scenario, I would use a Frame rather that tabs. The frame allows you to manage the flow of it's content via the NavigationService. You can use Uri's to display a page via the Frame.Source property, or a FrameworkElement via the Frame.Content property. Both are DependencyProperties and can therefore be bound to.
Paul Stovel wrote an excellent blog on this called WPF Navigation. Everything you need to create a wizard from a frame can be found in this blog, including passing values between pages and templating of the Frame to simply handle the display of navigation buttons.
I would agree with Mark, it is a lot easier to use NavigationWindows than TabControls.
I've worked on a lot of interfaces like this and written up some of the basic things with,
WPF Wizards, Part 1
WPF Wizards, Part 2
Then more recently I worked out how to get the styling just right
Styling Wizards
In fact I've released the styling and examples as open source at
WinChrome
There is some simple example code including use of a navigation list to the left with,
WinChrome.Win7Demo
Hope this helps

How to manage code in multitab application?

I'm making application in .NET C#.
It is not my choice but it has to be "multi-tab" application.
I have one window with tab control with many tabs.
There are many controls on every tab. Now all my event handlers and stuff is in main window file.
How to manage this program.
Is there any way to keep content of every tab in separate file (maybe class)?
Can use a frame and reference a page or user control
<TabControl>
<TabItem Header="Tab1 Page">
<Frame Source="TabPage.xaml" NavigationUIVisibility="Hidden" />
</TabItem>
<TabItem Header="Tab2 User Control">
<Frame Source="UserControl1Tab.xaml" />
</TabItem>
</TabControl>
A User Control is probably cleaner but I use Page out of habit.
They both have code behind for event handlers.
If you need to pass data then can do it in the ctor (but then you cannot assign the Source in XAML).

Attach a single close button on the tabcontrol in C#

How i can attach a single close button on the tabcontrol in C#.
There is a many way to attach a close button individually on each tabpages but I want to attach only single(e.g.) we can see on microsoft visual stdio 2008.
So Plz help me.
Here is a cheap way to do it, which might get you started:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<TabControl DockPanel.Dock="Top">
<TabItem Header="Test1" />
<TabItem Header="Test2" />
<TabItem Header="Test3" />
<TabItem Focusable="False">
<TabItem.Header>
<Button Command="{Binding CloseTab}" Content="X" Width="21" HorizontalAlignment="Stretch" />
</TabItem.Header>
</TabItem>
</TabControl>
</DockPanel>
</Window>
You then are left to implement a public ICommand CloseTab field or property on your DataContext, and style the tab control to your liking.
Edit:
If you use this method:
Wiring up the button is tricky. You have to be careful not to close the tab that contains the button
This isn't well adapted to dynamically created tabs, because you have to ensure the close button is appended to the list
You have to figure out how to re-select the last selected tab, when you close the selected tab
You'll also have weird behavior when tabs start to wrap
The tab-stop behavior is hard to get right. You can't make the last TabItem focusable, since focus is used to determine what to close, but tabbing to the close button breaks the normal TabItem keyboard flow
I have come up with a style that makes the button look like a regular tab, with a bold X on it, which makes it visually more like IE8, and fixes the keyboard selection problem. But it is complicated, and this solution is complicated enough.
Ultimately, a close button on every tab jives better with the tab control's default behavior. The only problem with that solution is that it takes up more space. You could cheat and make the close button collapse until you mouse over the tab item, though that's sort of a user-experience no-no, unless you just shrink it.
If you are serious about following through with the separate close button, I suggest you look at this article, and adapt what they do for the scroll buttons to your close button:
http://www.blogs.intuidev.com/post/2010/02/10/TabControlStyling_PartThree.aspx
Ignore what they do for close buttons :)
Would it be possible to have your tabcontrol on another container control and let that control's close button do the job?

Categories

Resources