XTab's Blog

Ged Mead's Blog at vbCity

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

AugSeptember 2007Oct
SMTWTFS
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

Archives

Topics

Ramblings

VB.NET

Monday, September 10, 2007 #

     WPF Layout - The StackPanel

Introduction

 One of the more basic panels provided in WPF is the StackPanel. As you would expect, it stacks its child elements one after the other - by default stacking them vertically. You can however override this setting and change the Orientation to Horizontal. As with the WrapPanel, I think that in the majority of cases you will use this panel as part of a larger, more complex display.

 To begin with, to see an example of it as the root element, you can use the following code snippet, which simply stacks a TextBlock and three Buttons vertically:

StackPanel As Root Element

Code Copy
<Window x:Class="StackPanelSingle"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Demo" Height="180" Width="180" MinHeight="165" MinWidth="140">

    <StackPanel >
       <TextBlock Margin="6" Padding="3" HorizontalAlignment="Center"
          FontFamily
="Verdana" FontSize="12" FontWeight="Bold">
          Make a choice:
       </TextBlock>
       <Button Margin="3,8,3,4" Padding="2"> Do Something </Button>
       <Button Margin="3,4,3,4" Padding="2"> Something Else </Button>
       <Button Margin="3,4,3,4" Padding="2"> Something Else </Button>
    </StackPanel>

</
Window>

 When run, the display looks like this:-

 StackPanel As Root Element

 You may have noticed that I inserted MinHeight and MinWidth values to ensure that all the items remain visible.

 I didn't however set maximum widths or heights (although I could have), so when the size is increased, so is the width of the buttons and the amount of unused lower window increased.

 

 Often this will not be what you want as the display can soon become disproportionate. You could use the Window's MaxWidth and MaxHeight properties to restrict the total size of the display. Alternatively you can set the HorizontalAlignment property of the Buttons so that they are changed from the default of "Stretch" (as demonstrated in the screenshot above) to a setting of "Center".

 With this change made, the Buttons remain at the correct size needed to display their content (which in this case is simple text). As the form is enlarged the Buttons remain at their original size, but move within the StackPanel so that they remain centered.

 

 You can still set MaxWidth (and Max Height) values on the Window if you wish.

Code Copy
Title="Demo" Height="180" Width="180" MinHeight="165" MinWidth="140" MaxWidth="300">

 So the amended XAML now would only allow the following display width to be set by the user:

 MaxWidth Value Set on StackPanel

StackPanel As Child Element

 The following example places two StackPanels side by side in a Grid. (We will be dealing with the very versatile Grid control next). The first panel has the default orientation of Vertical; the second one has its Orientation set to "Horizontal".

 

  The XAML code used is as follows:

Code Copy
<Window x:Class="StackPanelDemo1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="StackPanelDemo1" Height="300" Width="660">
    <Grid >

    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <StackPanel >
     <TextBlock Margin="6" Padding="3" HorizontalAlignment="Center" FontFamily="Verdana" FontSize="12" FontWeight="Bold"> Make a choice:  </TextBlock>
     <Button Margin="3,8,3,4" Padding="2"> Do Something </Button>
     <Button Margin="3,4,3,4" Padding="2"> Something Else </Button>
     <Button Margin="3,4,3,4" Padding="2"> Something Else </Button>
    </StackPanel>

    <Border Grid.Column="1" BorderBrush="Black" BorderThickness="4" Margin="5" Background="LightBlue"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"  >
      <StackPanel Orientation="Horizontal" >
        <ListBox Margin="3,3,9,3" Padding="2" HorizontalAlignment="Center">
          <ListBoxItem>  Document 1  </ListBoxItem>
          <ListBoxItem>  Document 2  </ListBoxItem>
          <ListBoxItem>  Document 3  </ListBoxItem>
        </ListBox>

        <ListBox Margin="3,3,29,3" Padding="2" >
          <ListBoxItem>  Page 1  </ListBoxItem>
          <ListBoxItem>  Page 2 </ListBoxItem>
          <ListBoxItem>  Page 3  </ListBoxItem>
        </ListBox>

       <DocumentViewer Grid.Column="1"   Margin="2" Name="DocumentViewer1" Width="322" />
      </StackPanel>
     </Border>
    </Grid>
</
Window>

 I think you can quite clearly see the nesting used. Just for display clarity, to show the two separate entities I enclosed the second StackPanel in a Border, but as you will discover later there are several other ways of delineating available to you. The Grid ColumnDefinition Width setting decree that the widths of both parts are sufficiently wide to accommodate the content, but don't stretch the content if the Window width is increased.

 We could do much more to improve this display, but for now the purpose of this item is to introduce you to the basic StackPanel and see it in action. Used as part of a larger display it can be a very handy tool.

posted @ 11:19 AM

Styles in WPF (2)- Styles, Resources and ResourceDictionaries 

Introduction

 In the first part of this article, we looked at a simple style that was created and applied to a set of Buttons. Each button has the same Background, Foreground, MinWidth, MinHeight, Margin and Padding. The resulting display looked like this:

  Original Five Buttons in a WrapPanel

 In point of fact, the amount of code reduction in that example was small. That's because the example uses only five buttons. But of course if the project had, say, 50, 100 or 200 buttons all using the same Style then the saving would be much greater.

 That leads me nicely into something I need to cover regarding accessibility of styles. The one I've used for the buttons is rather tightly locked down. Currently its scope is limited to that one particular WrapPanel.

 Here is the original code:

Code Copy
<WrapPanel x:Name="ButtonPanel" Background="Gainsboro">

<
WrapPanel.Resources>
<Style x:Key="BlackButton" >
<Setter Property="Button.Background" Value="Black" />
<
Setter Property="Button.Foreground" Value="White" />
<
Setter Property="Button.Margin" Value="12,3,12,3" />
<
Setter Property="Button.Padding" Value="3"  />
<
Setter Property="Button.MinWidth" Value="75" />
<
Setter Property="Button.MinHeight" Value="34" />
</Style>
</WrapPanel.Resources>

<
Button Style="{StaticResource BlackButton}">Open Button</Button>
<
Button Style="{StaticResource BlackButton}">Close Button</Button>
<
Button Style="{StaticResource BlackButton}">StartButton</Button>
<
Button Style="{StaticResource BlackButton}">Pause Button</Button>
<
Button Style="{StaticResource BlackButton}">StopButton</Button>
</
WrapPanel>

 A minor tweak that saves repetition is to assign the type of control to the TargetType. In this case of course the TargetType would be Button. It would then not be necessary to fully qualify the control name, as we have done (e.g. Button.Background, Button.Foreground, etc).

 The alternative code would be:

Code Copy
<Style x:Key="BlackButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black" />
<
Setter Property="Foreground" Value="White" />
<
Setter Property="Margin" Value="12,3,12,3" />
<
Setter Property="Padding" Value="3"  />
<
Setter Property="MinWidth" Value="75" />
<
Setter Property="MinHeight" Value="34" />
</Style>

 Note also that you can assign the more generic type of "Control" to the TargetType, i.e.:

     TargetType="{x:Type Control}" .

The style will then be available to all controls - any irrelevant properties being ignored.

Window Resources

 Let's start with where we might want to place that Style so that we can widen its scope. If those five buttons in the WrapPanel are the only ones we want to style in that way in this application then the code can happily be left as-is. However if we maybe want to use that button style elsewhere in the same Window, then all you have to do is cut and paste the Style out of the WrapPanel Resources and into the Window Resources:

Code Copy
<Window.Resources>
<Style x:Key="BlackButton" >
<Setter Property="Button.Background" Value="Black" />
<
Setter Property="Button.Foreground" Value="White" />
<
Setter Property="Button.Margin" Value="12,3,12,3" />
<
Setter Property="Button.Padding" Value="3"  />
<
Setter Property="Button.MinWidth" Value="75" />
<
Setter Property="Button.MinHeight" Value="34" />
</Style>
</Window.Resources>

<WrapPanel x:Name="ButtonPanel" Background="Gainsboro">
<Button Style="{StaticResource BlackButton}">Open Button</Button>
<
Button Style="{StaticResource BlackButton}">Close Button</Button>
<
Button Style="{StaticResource BlackButton}">StartButton</Button>
<
Button Style="{StaticResource BlackButton}">Pause Button</Button>
<
Button Style="{StaticResource BlackButton}">StopButton</Button>
</
WrapPanel>

 The Style will also be available for any other Button in that Window.

Application-wide Resources
 Moving further up the hierarchy, if the Style is to be used in more than one file across the project then the next place to consider is the Application.xaml file. This file is automatically created for you when you set up a new project. The only change needed from the previous example is the obvious one of changing the "< Window.Resources >" to "< Application.Resources >" when you cut and paste it from the Window xaml file to Application.xaml.

  If you omit the Key from the Style then that particular style becomes the default style for all buttons in the application. (The "key", you may remember from earlier blogs, represents the name of this style and you can use it to identify exactly which style you want to apply to individual controls).
This blanket coverage isn't set in tablets of stone, though. If you want to override the default style with another one of your choice then you simply assign the style name as in previous examples.

Code Copy
<!-- The first button uses the default style from Application.xaml-->
<
Button >Open Button</Button>
<!-- The next button uses a different Style -->

<
Button Style="{StaticResource GirlieButton}">Close Button</Button>
<!-- The remaining buttons use the default style from Application.xaml-->
<Button>StartButton</Button>
<
Button>Pause Button</Button>
<
Button>StopButton</Button>

 and you get something like this:

 For completeness (although I don't think you'll be needing it any time soon!), here's the Style code (which I placed in Window.Resources):

Code Copy
<Style x:Key="GirlieButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Pink" />
<
Setter Property="Foreground" Value="Black" />
<
Setter Property="Margin" Value="12,3,12,3" />
<
Setter Property="Padding" Value="3"  />
<
Setter Property="MinWidth" Value="75" />
<
Setter Property="MinHeight" Value="34" />
</Style>

 There is however an alternative to pasting the Styles directly into Application.xaml and some people do prefer to take this route. That is to create one or more ResourceDictionaries and to place the dictionary or dictionaries in the Application's Resources markup. If for no better reason, this approach is worth considering because it keep the Styles neatly compartmentalized and also makes it very easy to lift a "Style File" ResourceDictionary from one project and reuse it in another one. It also reduces clutter in Application.xaml.


Resource Dictionary
It's simple to add a new ResourceDictionary to the project. Select "Project" from the top line menu and you will be able to select "Add Resource Dictionary" from the context menu that appears:

 Choose a name for it - I used "ButtonStyles" and add it to the project. The skeleton code in the xaml file looks like this:

Code Copy
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

</
ResourceDictionary>

 Once again, you can Cut and Paste the Style from wherever it currently sits (WrapPanel.Resources, Window.Resources or Application.Resources and paste it into the ResourceDictionary file. At his point, or in fact at any time in the future you can add further styles to this ResourceDictionary. This is a plus. Even better, if you subsequently decide that you want all the text on these buttons to be Yellow instead of White, then you only have to make the change in one place (the Style in the ResourceDictionary) and it will automatically be propagated throughout the application. If you're familiar with CSS you'll see the similarities.

 There is one more task needed to make the ResourceDictionary(ies) universally available. You have to place it or them inside a MergedDictionaries collection ... yep, even if there is only one of them! This code in the Application.xaml file will do the trick:

Code Copy
  <Application.Resources>
   <
ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</
Application.Resources>

 

 And of course if you do happen to have more than one ResourceDictionary then you just add them inside the MergedDictionaries collection tags:

Code Copy
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyles.xaml"/>
<
ResourceDictionary Source="Dictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>

Just adding as many as you need as time goes on.

 Although this part hasn't covered much in the way of the Styles themselves, I hope the explanation of where to place the Styles for the scope you require and how to access those Styles is helpful to you. Initially I found the syntax for getting the application to find the styles in ResourceDictionaries a bit difficult to grasp, so I hope that this too is useful for you. In the next Part I will dig deeper into some more things you can include in Styles.

posted @ 11:17 AM | Feedback (1)