How to manage code in multitab application? - c#

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).

Related

WPF - Prism : Show regions in dialog window

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.

Create an instance of a C# class from inside XAML

I have a working application that has been written in C#, and I now want to extend that application to allow the user to switch between viewing the application, and viewing a built in web browser (inside the same application window).
I also have a separate working web browser, that has also been written in C#.
I have just added the functionality to the original application to include 'tabbed' displays, where the original application will be displayed on the first tab, and a built in web browser on the second tab.
The 'tabbed' displays for the application have been created using XAML markup in Visual Studio. I now want to add an instance of the Web browser that has also been written in C# to the second tab that I have created in the XAML markup.
It would be something like:
<TabControl>
<TabItem Header="Browser">
<StackPanel>
<!-- Call/ instantiate the browser here -->
</StackPanel>
</TabItem>
</TabControl>
But I have no idea how I call/ create an instance of the browser from within the XAML markup...
The browser has been created using C#:
namespace Agent
{
public partial class Browser : Form
{
public Browser()
{
...
}
}
}
Can anyone explain to me how a create an instance of Browser inside the ` of the XAML markup?
Edit
Ok, so I have edited my XAML markup as recommended in the answer that's been suggested- I now have:
<Window ...
xmlns:Agent="clr-namespace:Agent"
...>
<Grid>
...
<TabControl>
<TabItem Header="R">
<StackPanel>
...
</StackPanel>
</TabItem>
<TabItem Header="Browser">
<Agent:Browser x:Name="Browser" />
</TabItem>
</TabControl>
</Grid>
</Window>
I have also updated my Browser.cs class, so that it is now extending UserControl, rather than Form:
public partial class Browser : UserControl{
However, I am getting a compile error on the line:
<Agent:Browser x:Name="Browser" />
which says:
The name "Browser" does not exist in the namespace "clr-namespace:Agent".
But clearly Browser does exist in Agent, as shown by the code I've included here... In fact, when typing the line <Agent:Browser x:Name="Browser />, when I typed the :, Browser was one of the options that came up in the autocomplete menu...
What am I doing wrong here? Why doesn't the compiler think that Browser exists inside Agent?
The key to instantiating any object in XAML is to make sure the namespace is declared. You can provide any XML prefix and assign it to your CLR namespace (ref) and it will act like a using statement. For example:
<TabControl xmlns:agent="clr-namespace:Agent">
<TabItem Header="Browser">
<StackPanel>
<agent:Browser/>
</StackPanel>
</TabItem>
</TabControl>
NOTE: your object has to extend UIElement (or one of its children) for it to work in a XAML tree. If your control is a WinForms control you either need to find the equivalent XAML control or wrap it in a WindowsFormsHost (ref).
WPF vs. WinForms
The purpose of this section is to help recognize which platform code is by namespace, as well as some of the trade-offs. I've used both and can say from experience that they each have good points and... not so good points.
WinForms classes live in the System.Windows.Forms namespace, and are available by referencing the System.Windows.Forms.dll assembly.
WPF classes live in the System.Windows and System.Windows.Controls namespaces, and are available by referencing a set of DLLs
WinForms rendering is immediate. That means you are working against bitmaps and you are responsible for clearing and redrawing stuff yourself (usually you can just call Invalidate()). If you do heavy image bit manipulation, WinForms is easier to work with.
WPF rendering is declarative. That means more work is offloaded to your GPU and you just tell it how to draw stuff. You can also use GPU render shaders for special effects. WPF has a nicer look out of the box, but it has a reputation for making easy things difficult but impossible things possible.
WinForms is easier to learn, but has a dated look out of the box.
WPF is built around data binding, enabling the UI to update in response to property values automatically. It's also able to be completely restyled, although that is quite an undertaking.
If you are just getting started, I'd go ahead and bite the bullet to start the heavier learning curve for WPF. It will provide a basic understanding that transfers to other platforms like Windows Store apps, etc.
Firstly you need to place that tag inside of your UserControl opening tag like so:
<UserControl x:Class="View.testControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Agent="clr-namespace:Agent">
Then you can use it like this:
<TabControl>
<TabItem Header="R">
<StackPanel>
...
</StackPanel>
</TabItem>
<TabItem Header="Browser">
<Agent:Browser x:Name="Browser" />
</TabItem>
</TabControl>
EDIT
From what you told me in the comments you will need to create a Custom Control in your WPF project. To do that you need to:
Right Click your Project;
Select Add New Item;
From Installed (which is in the left column) select WPF;
From the list in the middle column select Custom Control;
Now you can create that control in your XAML with xmlns attribute.
Here is a great example from msdn on how to create custom controls

Load .xaml page into textbox in wpf

Hi I have a problem with loading .xaml page to textbox located in MainWindow. In previous implementation I used tabs, so I could simply write something like this
<TabItem Header="First Tab" Name="firstTab">
<Frame Background="White" Name="firstTabFrame" Source="Tabs/firstTab.xaml/>
</TabItem>
Which propably handled enabled to load firstTab.xaml into mainPage.
Now I have a Ribbon in which I have some kind of groups etc. How to load page firstTab.xaml into my mainPage (maybe to textbox? grid?) after clicking RibbonMenuButton clicked.

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

Create a tabbed WPF menu, "ESET Antivirus" - Style

I'm looking for a way to create an application layout for a little tool that looks like the ESET Antivirus UI:
I thought, that I take a TabControl and do a complete Restyling on this whole thing. I created a basic tab layout:
<Grid Background="White" Grid.Row="1" >
<TabControl TabStripPlacement="Left">
<TabItem Header="Dashboard">
<Grid>
</Grid>
</TabItem>
<TabItem Header="Projects">
<Grid>
</Grid>
</TabItem>
<TabItem Header="Settings">
<Grid>
</Grid>
</TabItem>
<TabItem Header="Help & Info">
<Grid>
</Grid>
</TabItem>
</TabControl>
</Grid>
However, I don't have the slightest clue how to get the tabs the way I'd like them to be. I tried a lot with Blend to get the Tabs look the image above, but I don't get it. The triangle would be a nice to have, but the highlighting should be adapted.
Any advice?
Whenever you are having trouble with trying to make WPF UI elements look exactly the way you want, you should go find the default <style> XAML from microsoft and try modifying that directly in your project until you get the desired result.
In case that wasn't clear, you you need to do is follow the links below, copy the style from the pages and put them into the Resources section of your window (or App.xaml, its really up to you). Then fiddle with them until you get it to look the way you want.
The two styles you'll need to play with are TabControl and TabItem
I'd think to a MVVM approach, instead.
Before all, shape the model of the data, as well as the business layer (commands, functions, etc.).
Then, you can "wear" your model (by leveraging a ViewModel) with a ListBox, for the left selector, and a simple ContentControl for the main part.
The selected item of the ListBox should be fed into the content of the body, and a DataTemplateSelector (for instance) will choose the proper visual fragment.
It's just a suggestion. Personally, I've found a bit tricky the TabControl and I seldom use it.
Cheers
An old trick is to have 2 different sets of images - one for clicked and one for passive (maybe one for mouseover) but clicked image will have the triangle in it.
This uses static images for buttons, which is very easy to use, but hard to modify on the fly.

Categories

Resources