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.
Related
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
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
I am pretty new to WPF, and in order to get some knowledge I decided to make a very simple UML modeling program, that basically offers the possibility to put some classes onto a canvas, connect them and move them around.
Now to the question:
I have been thinking about letting the classes I put on the canvas being a userControl I design. In my mind it would be something like a Grid, with some textboxes to represent properties, attributes and so on. The actual question is then, is my idea possible, or should I go with something completely different? My concern right now is how to implement the grid such that it can expand (add a row) under the right heading (Attribute/property..) when I want it to, and not be expanded to a maximum from the beginning.
I hope you can understand my question, and give me an idea to whether I should continue to implement it how I thought about, or do it using some other method.
You may wish to consider a ListView control, perhaps with an Expander, something like this:
<Canvas>
<Expander Header="Stuff"
MaxHeight="900"
Canvas.Left="202"
Canvas.Top="110">
<ListView Name="MyListView">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add new thing"
Click="MenuItem_Click" />
</ContextMenu>
</ListView.ContextMenu>
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Label>Name</Label>
<TextBox Text="Value" />
</StackPanel>
</ListViewItem>
<ListViewItem>Item two</ListViewItem>
<ListViewItem>Item three</ListViewItem>
</ListView>
</Expander>
</Canvas>
This will size as needed up to the max given. The list view items could contain any sort of content (not just text) as you can see above. You will want to learn a bit about Style and Control templates. WPF has IMHO a rather steep learning curve but there are a lot of learning resources on the web. Good luck.
In response to your comment, I'm adding additional information.
Anything you can do in XAML you can do in code behind (mostly XAML just calls framework objects). In this case I've added a context menu to the ListView control. This menu contains one item "Add new thing". There is a Click event for this item which is bound to the MenuItem_Click method in the code behind. I then added this method to the code:
void MenuItem_Click(object sender, RoutedEventArgs e) {
var lvi = new ListViewItem();
lvi.Content = String.Format("New thing {0}", DateTime.Now);
MyListView.Items.Add(lvi);
}
Now if you right click in the ListView you will see the "Add new thing" menu selection, left clicking it adds a new ListViewItem into the ListView (programmatically).
What are the best practices for designing a simple component, for example a border with a background, rounded corners and a textblock with specific styling inside? What I need to be able to do is add this component on many different objects (basically a styled label for the items). The easiest way to design such a thing, in my opinion, is via XAML, but how do I create more of these objects from the code behind?
Another option would of course to just write it all in code, but it is much slower to design the look by just looking at code. I tried googling around a bit but I suppose I am simply not figuring out the correct keywords because I was unable to find anything of use.
I think there are multiple ways of doing this. Depends on what exactly you want to achieve. You would want to read up on the following in WPF
1. UserControls
2. CustomControls
3. Styles
4. Templates
5. Resources
You could use a ContentControl and set its template. Your template would be the border/background/rounded corners etc...
<DataTemplate x:Key="MyTemplate">
<Border>
...
<TextBlock Text="{TemplateBinding Content}" />
...
</Border>
</DataTemplate >
You'd use it like this:
<ContentControl ContentTemplate="{StaticResource MyTemplate}" Content="blah blah" />
Is it possible to open another Window in a TabControl's TabItem?
The reason I want to do this is that if I have 5 TabItems in my TabControl, the one Window file I'm coding all these TabItems and their associated actions will get very large. So it would be nice if it was possible to to give each TabItem its own Window file.
Or how do you solve the problem where theWindow file controlling the TabControl gets too large?
<Window ...
xmlns:local="clr-namespace:MyNamespace"
>
<TabControl>
<TabItem Header="FirstTab">
<local:MyFirstTabUserControl/>
</TabItem>
<TabItem Header="SecondTab">
<local:MySecondTabUserControl/>
</TabItem>
<TabItem Header="ThirdTab">
<local:MyThirdTabUserControl/>
</TabItem>
</TabControl>
</Window>
Your each TabUserControl is actually simple UserControl, since TabItem can host any control as its own child.
You have several choices:
add one or more resource dictionaries to your app that contain resources with templates and styles for the various views you host in your tabs. This approach works well if you just need to maintain separation of the visual trees only.
create user controls for each view (with own XAML and class file) and use one instance for each different view in the tabs. This approach allows you to encapsulated specific business logic and the corresponding visual tree together.
generate some of the UI from code. This one has no advantages, except t makes you XAML smaller. And is your .cs files become too big, you can always split them in multiple code files and use partial classes. (just had to throw in this one for completeness :-))
You can also set the TabItem Content equals to your Window content
ex: [WindowType is your window]
WindowsType oWindow = new WindowType();
TabItem oTab = new TabItem();
oTab.Content = oWindow.Content;
Make a UserControl for each TabItem.
You can use a UserControl as was mentioned already.
But you can also use the Page control. Each "Window" would be a page, and the tab would have a NavigationControl in it. I've used this approach before and it works well. I prefer the UserControl route, but both are valid.