Archive for the ‘WPF’ tag
ScrollBar control template in wpf
Won’t it be cool to have ones own scroll bar. Felling the same, I did a quick peek in to msdn and there was a sample scroll bar template. The example is really good, but it did not talk about the internals of a scroll bar. So i thought I will write about it.
The two arrows that you see at the ends are called RepeatButtons. The middle field (light grayish one) is called Track. The middle, movable portion in the track is called Thumb and the partitions to the left and the right of the thumb are two more repeat buttons.
I have named these controls with some number so that it can easily be related to the code.
<!-- We are going to alter the vertical scroll bar's template --> <ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}"> <!-- First up is the background panel for all the above mentioned controls --> <Grid Background="Transparent"> <Grid.RowDefinitions> <RowDefinition MaxHeight="50"/> <!-- Up arrow row --> <RowDefinition Height="0.00001*"/> <!-- Track row --> <RowDefinition MaxHeight="50"/> <!-- Down arrow row --> </Grid.RowDefinitions> <Border Grid.RowSpan="3" CornerRadius="2" Background="DarkGray" Opacity="1" /> <!-- Border for the scroll bar --> <RepeatButton Grid.Row="0" Command="ScrollBar.LineUpCommand" Width="30" Height="30">Up</RepeatButton> <!-- Repeat button 1 (up arrow) --> <Track Name="PART_Track" Grid.Row="1" IsDirectionReversed="true"> <!-- Track --> <Track.DecreaseRepeatButton> <RepeatButton Command="ScrollBar.PageUpCommand" Opacity="0" /> <!-- Repeat button 3 (left partition) --> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Margin="1,0,1,0" Background="Transparent" Opacity="0.3" Width="20" /> <!-- Thumb --> </Track.Thumb> <Track.IncreaseRepeatButton> <RepeatButton Command="ScrollBar.PageDownCommand" Opacity="0" /> <!-- Repeat button 4 (right partition) --> </Track.IncreaseRepeatButton> </Track> <RepeatButton Grid.Row="2" Command="ScrollBar.LineDownCommand" Width="30" Height="30">Down</RepeatButton> <!-- Repeat button 2 (down arrow) --> </Grid> </ControlTemplate>
I hope the above snippet is self explanatory, still a bit of explanation.
- We start off altering the ControlTemplate of the ScrollBar.
- We place a grid as the base panel for the scroll bar and we divide it in to three rows, one for up arrow, one for track and one for down arrow.
- Then we add two repeat buttons to the top and the bottom most rows (up and down arrows).
- Now comes the middle row for the track. As mentioned earlier, a track is again composed of two repeat buttons (actually the partitions are made of buttons; really don’t know why) so we create those buttons and assign them the scroll bar related commands.
- We also add a thumb in the middle. Make sure that you don’t set any Height for the thumb as this is a vertical scroll bar (no width for the horizontal scroll bar). Don’t bother about the opacity that I have given for these controls. We are free to modify them.
After the control template creation modification, we need to assign this to our scroll bar.
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}"> <Setter Property="SnapsToDevicePixels" Value="True"/> <Setter Property="OverridesDefaultStyle" Value="true"/> <Style.Triggers> <Trigger Property="Orientation" Value="Vertical"> <!-- Our scroll bar is a vertical one. Thats why --> <Setter Property="Width" Value="18"/> <Setter Property="Height" Value="Auto" /> <Setter Property="Template" Value="{StaticResource VerticalScrollBar}" /> </Trigger> </Style.Triggers> </Style>
Thats it. You have successfully altered a scroll bar.
Update – Don’t try changing the PART_Track. Changing the name will lead to an incomplete scroll bar as that name has been used by .NET WPF framework.
DoUNo: XAML gets compiled in to a BAML
What does a xaml file gets compiled in to ? It gets compiled in to a baml (binary xaml). More @ wikipedia.
You can find the .baml file in the \obj\Debug folder.
Transparent background with opaque controls on top of it in wpf
Ever felt like having a transparent window background and still opaque controls inside the window? It can be easily done in wpf.
- Set the window’s AllowsTransparency to True
- Set the window’s Background to Transparent
- Add a Rectangle to the parent panel of the window
- Set the opacity of the rectangle to some value < 1 (0.7, …)
- Add your controls to the parent panel
- You are one step away form seeing a transparent background with opaque controls on top of it. Go ahead, run the application now
Sample window,
<Window x:Class=”BackgroundWindow.Transparent.Samples.WPF.Window1″
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Window1″ Height=”300″ Width=”300″ AllowsTransparency=”True” Background=”Transparent” WindowStyle=”None”>
<Grid>
<Rectangle Fill=”Gray” Opacity=”0.7″ />
<Button Width=”100″ Height=”100″>Click this on</Button>
</Grid>
</Window>
DoUNo: MDI in WPF
WPF, out of the box doesn’t have provision for MDI windows. The reason is quite simple, MDI windows are outdated and most of the applications have been using tabbed documents, proving they are really easy to use. Although the framework is flexible enough for you to make such a feature, its better to move to tab based interface.
DoUNo: Popup animation in wpf
Every time I try adding a default animation (Slide, Fade, …) to a pop up in WPF, I find it not to be working. Today, I went thru’ MSDN (breaking my laziness
) and found that the popup animation shall work only if the AllowsTransparency of the popup is set to true. Really weird !!
WrapPanel in WPF
In my previous post I had written about StackPanel. One big disadvantage with the StackPanel was with the wrapping part. It cannot wrap controls / contents when it overflows. Thats why we have the WrapPanel. This is StackPanel + Wrap enabled. The following example may help you understand this better.
Consider that you have a stack panel with 7 buttons arranged in a horizontal fashion and if your window’s width is smaller than the sum of seven button’s width, then this how it looks
<Window x:Class="LayoutsTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel Orientation="Horizontal">
<Button Content="Button1" VerticalAlignment="Center" />
<Button Content="Button2" VerticalAlignment="Center" />
<Button Content="Button3" VerticalAlignment="Center" />
<Button Content="Button4" VerticalAlignment="Center" />
<Button Content="Button5" VerticalAlignment="Center" />
<Button Content="Button6" VerticalAlignment="Center" />
<Button Content="Button7" VerticalAlignment="Center" />
</StackPanel>
</Window>
A close substitute for this problem will be a WrapPanel.
<Window x:Class="LayoutsTest.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <WrapPanel Orientation="Horizontal"><Button Content="Button1" VerticalAlignment="Center" /> <Button Content="Button2" VerticalAlignment="Center" /> <Button Content="Button3" VerticalAlignment="Center" /> <Button Content="Button4" VerticalAlignment="Center" /> <Button Content="Button5" VerticalAlignment="Center" /> <Button Content="Button6" VerticalAlignment="Center" /> <Button Content="Button7" VerticalAlignment="Center" /> </WrapPanel> </Window>
Although this solves the Wrap problem of the stack panel, still we cannot place two controls paralle to each other using this panel.
DockPanel in WPF
As the name says you can dock your controls in to either Top, Left, Right or Bottom of the panel. Placing a control to a location can be done using the Dock property with the values Left, Top, Right and Bottom.
ln1: <DockPanel> ln2: <Button DockPanel.Dock="Top" Content="Button1" /> ln3: <Button DockPanel.Dock="Bottom" Content="Button2" /> ln4: <Button DockPanel.Dock="Left" Content="Button3" /> ln5: <Button DockPanel.Dock="Right" Content="Button4" /> ln6: <Button Content="Button5" /> ln7: </DockPanel>
This will dock the button1 to the top of the container, button2 to the bottom and so on.
The order in which we dock the controls matters in here. If we move ln4 to ln3 and ln3 to ln4, the layout will look different.
If you dock a control to a location, the control will remain docked to that location irrespective to the size of the container. Take a look at the schreenshot shown below (with the container maximised).
Although this allows us to fix some controls to any edge of the container, we cannot position controls explicitly using this panel.
StackPanel (Layout) in WPF
Like .Net 2.0, WPF provides a set of layouts that allows the users to easily place the controls in to it. Lets look in to it, one by one comparing with the net 2.0 version of it.
StackLayout
This was called as FlowLayout in .net 2. Controls that are added in to this layout will be automatically aligned either in a vertical or in a horizontal fashion. This alignment depends on the value of Orientaion property. The value can either be Vertical or Horizontal.
Vertical Orientation
<StackPanel Orientation="Vertical"> <Button Content="Button1" /> <Button Content="Button2" /> </StackPanel>
Horizontal Orientation
<StackPanel Orientation="Horizontal"> <Button Content="Button1" /> <Button Content="Button2" /> </StackPanel>
If you notice the screenshots, you will find that the width of the button is automatically controlled by the WPF framework. Thats why the buttons are stretched. But if you wanna control the width, you can play with the HorizontalAlignment property of the control. The default alignment is Stretched. Specifying a width for the control along with the HorizontalAlignment property allows you to have total control on the size and location of the control.
<StackPanel Orientation="Vertical"> <Button Content="Button1" /> <Button Content="Button2" HorizontalAlignment="Left" /> <Button Content="Button3" HorizontalAlignment="Right" /> <Button Content="Button4" HorizontalAlignment="Center" /> <Button Content="Button5" HorizontalAlignment="Stretch" /> </StackPanel>
We can see this layout in action in loads of places. For example, the search tool that comes with windows has employed this layout.
Although this layout lets the us relax on alignments, we cannot place two controls parallel to each other (this layout is not intented to do so. we have another layout for this, GridLayout). Also this layout cannot wrap controls when the controls overflow (again this layout is not intented to do so. we have another layout for this, WrapPanel).
Creating a single instance application in C#, WPF
Some time you might want the user to run only one instance of the application. Its pretty easy to do so in C#. This is acheived using a Mutex. A mutex is used to restrict the usage of common resources in concurrent proragmming. C# provides a class called System.Threading.Mutex with which we can control the number of instances of an application that should be running. Just add the following snippet to the App.xaml.cs file (code behind file of App.xaml)
class App : Application
{
private Mutex myMutex;
...
protected override void OnStartup(StartupEventArgs theArgs)
{
bool aIsNewInstance = false;
myMutex = new Mutex(true, "Foo.SingletonApp", out aIsNewInstance); //Creates a mutex for the application
if(!aIsNewInstance)
{
App.Current.Shutdow(); //Shutdown when a new mutex with the same name is created
}
}
}
How this works
The creation of a mutex in here takes three parameters. First one is to give the ownership of this mutex to the calling thread. Second one is the unique name given for this mutex (remember this is a unique name). Third one is an out parameter that returns
true — if there are no mutex with this name and if the new mutex is successfully created
fase — if there is already a mutex with this name.
That why we check for !aIsNewInstance in the snippet. Here we override the Startup event of the Application class (refer to my previous post on Application Events) so that we can validate the mutex during the start of the application.
WPF Application creation, an insight — part2
Before I can start with part2, a small highlights from part1.
- All the WPF applications are an object of System.Windows.Application running as a process
- Visual Studio allows the users to relax from the creation and running of the System.Windows.Application object if you specify the BuildAction as Application Definition
- Specifying the StartupUri attribute in the App.xaml with a window class allows the developer not to write snippets that will show the top level window
Accessing Application object from window classes
As soon as the Application object is created, it would be set to the Current property of itself. As this property is a static property, any window classes can access the instance of app that is running. Also the application object, as mentioned earlier, shall hold the instances of all the top level windows. So we can even access these top level window object from any class thru’ the Current.Windows property.
class Window1
{
public Window1() //constructor
{
foreach(Window aTopLevelWindow in App.Current.Windows as Window)
{
MessageBox.Show(aTopLevelWindow.Title);
}
}
}
Shutting down the Application object
While running an Application object is done thru’ Run(), we can shut down the app thru’ Shutdown(). For example, if you want to provider a custom close button in your window, you can close the application (terminate the entire process) using the following snippet,
class Window1
{
...
public void ExplicitShutDown() //Some method which will explicity shutdown the Application object
{
App.Current.Shutdown(); //Where App is the name of the Application class
}
}
This is called as an explicit shutdown.
Application Events
Here are some of the events of the Application object that can be of great use when you program.
- Startup — Invoked after the Application object is created and run. You can show your top level windows in here
- Activated and Deactivated — Invoked when one of the top level windows of the Application object is activated and deactivated will be called when another Application object’s top level window gets activated
- Session Ending — Invoked when windows session ends either by a shutdown call or a restart call
- Exit — Invoked when the Application.Shutdown() is called
Hope these two posts helped you in understanding how a WPF application gets instantiated. From my next post I will start writing about controls.







