#343 – Associating Multiple Controls with the Same Command

One benefit of using commands in WPF, as opposed to writing event handlers, is that it’s easier to link multiple controls to a single command.  With commands, you can create a single command object, bind it to a method, and then associate the command with more than one control by setting the Command property of each control.

In the example below, we associate the ApplicationCommands.Open command with both a Button and a MenuItem.

    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Open" Command="ApplicationCommands.Open"/>
        </ContextMenu>
    </Window.ContextMenu>

    <StackPanel>
        <Button Content="Open" Command="ApplicationCommands.Open" HorizontalAlignment="Center" />
    </StackPanel>

In the code-behind, we still only have to create a single CommandBinding instance.

		public MainWindow()
		{
			this.InitializeComponent();

            CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, Open_Executed, Open_CanExecute));
        }

        public void Open_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Open file code goes here");
        }

        public void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;   // Can we open file?
        }

#342 – Binding a Button to a Command

In WPF, the preferred method for executing some code when a button is clicked is to use a commandA command is an object that represents an action to be taken and is bound to a particular method that performs the action.  The button is then associated with the command by setting its Command property.

Here’s an example.

        <Button Content="Open" Command="ApplicationCommands.Open" />

ApplicationCommands.Open is a predefined command that is just a placeholder that you bind to some “open” logic in your application.  You do this by adding a new CommandBinding object to the parent window’s CommandBindings collection.

You specify handlers for the Executed and CanExecute events of the command.

		public MainWindow()
		{
			this.InitializeComponent();

            CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, Open_Executed, Open_CanExecute));
        }

        public void Open_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            // Open file here
        }

        public void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;   // Can we open file?
        }

#341 – Create a Button with an Image and Text

Since a Button is a ContentControl, it can have any other control as its content, rather than text.  You can include an Image control, to create a button with an image on its face.  You can also include multiple controls on the button, by settings its main content to be a container, which in turn contains other controls.

In the example below, we create a Button that has both an image and some text (a caption).

        <Button HorizontalAlignment="Center" VerticalAlignment="Center"
                Margin="10" >
            <StackPanel>
                <Image Source="Misc-Settings-icon.png" Height="64" Width="64"/>
                <Label Content="Settings" HorizontalAlignment="Center"/>
            </StackPanel>
        </Button>

#340 – Create a Button with an Image

To create a Button that has an image on the surface of the button, rather than text, you use an Image control as the content of the button.

You need to tell the Image control where to find its image.  The easiest way to locate images is to just include them as resources in your project.

  • Embed the image as a binary resource in your project
  • Set the Build Action of the image to Resource
  • Use the filename as the image’s Source

In the example below, we’ve added the Misc-Settings-icon.png file to our project.

We can then create a Button that has this image as its main content.  Because Button is a ContentControl, it can contain another control as its content.

    <StackPanel>
        <Button HorizontalAlignment="Center" VerticalAlignment="Center"
                Margin="10" >
            <Image Source="Misc-Settings-icon.png" Height="64" Width="64"/>
        </Button>
        <Label Content="That's a button up there.." HorizontalAlignment="Center"/>
    </StackPanel>

#339 – Wrapping a Button’s Text Content to Multiple Lines

When a Button control automatically sizes to fit its content, it will grow to fit the text in the Content property.  However, the text will always remain on a single line.

        <Button Content="Click me if you want to see something cool.  In fact, click as many times as you like."
                HorizontalAlignment="Center" VerticalAlignment="Center"


If you constrain the button’s Width, however, the text will be clipped.

To get the text on a face of a Button to wrap, you can use a TextBlock as the button’s Content, rather than a simple text string.  You also set the TextWrapping property on the TextBlock.

        <Button HorizontalAlignment="Center" VerticalAlignment="Center"
                Margin="10" Width="120">
            <TextBlock Text="Click me if you want to see something cool.  In fact, click as many times as you like."
                       TextWrapping="Wrap"/>
        </Button>

#338 – Setting a Control’s Foreground Color

We saw how to set the background of a control to a solid color by specifying a color value for the Background property.  Similarly, you can set the foreground color of a control using the Foreground property.  For controls that contain text, the foreground color is generally the color of the text.

Since the Foreground property’s type is System.Windows.Media.Brush, the property is set to an instance of a Brush object.  In XAML, you can set the property using the name of a predefined color, which maps to a predefined SolidColorBrush in the Brushes class.

        <Button Content="Take a Trip" Foreground="DarkViolet" Width="100" Margin="10"/>


Below is an image showing how some of the more common controls look when the Foreground property is set to a solid color.

#337 – Specifying Font Properties for All Controls In a Window

Because the various font-related properties are dependency properties, they can be set on a high-level element in the logical tree and “trickle down” to lower-level elements.  The lower-level elements inherit property values from higher-level elements.

In the example below, we specify a font to use for all child controls within a window.

<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
	x:Class="WpfApplication11.MainWindow"
	x:Name="Window"
	Title="Quotes"
	Width="780" Height="368"
    FontFamily="Georgia">

    <StackPanel>
        <Label Content="A nice quote:" Margin="20,10,20,0"/>

        <TextBlock Name="txt2" Margin="20" FontSize="18" TextWrapping="Wrap">
            Freedom is never dear at any price. It is the breath of life. What would a man not pay for living?<LineBreak/>
            --Mohandas Gandhi
        </TextBlock>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <RadioButton Content="Like" Margin="10"/>
            <RadioButton Content="Don't Like" Margin="10"/>
        </StackPanel>

        <Button Content="OK" FontFamily="Tahoma" Width="100" Margin="20"/>
    </StackPanel>


Notice that we can override an inherited property by setting it explicitly for a control. We specify that Tahoma should be the FontFamily for the Button control.

#336 – Intellisense Shows Fonts Available on Development System

When you use the XAML editor in Visual Studio 2010 to enter a value for the FontFamily property, Intellisense in the editor will show you a list of fonts available on the development system.  In the example below, the dropdown shows the Parsons font as a possible font choice, since it has been installed on the development system.

This font will appear correctly when the application is run on the development system, but will get displayed on a target system only if it is also installed on that system.  If the font is not present, some other font will be substituted.

#335 – How WPF Finds Fonts on a Target System

A WPF application specifies a font that it wants using the properties FontFamily, FontStyle, FontWeight, FontStretch and FontSize.  At runtime, WPF decides the exact font to use on the target system where the application is running. This decision is based on matching the first four properties (ignoring FontSize for the moment) to a physical font file that is installed on that system.

WPF starts by matching the supplied FontFamily against the names of the fonts found on the system.  It then tries to find a font that most closely matches the requested FontStretch, FontStyle and FontWeight property values.  Matching FontStretch is the highest priority, followed by FontStyle and then FontWeight.

If WPF can’t find a matching font, it “falls back” to a default font installed with WPF, C:\Windows\Fonts\GlobalUserInterface.CompositeFont.  This is a composite font that tries to map individual characters to fonts likely to be present on the system.

#334 – Specifying Values for FontFamily

The FontFamily property of a Control indicates what typeface the control’s text should be rendered in.  The value of the property can be the name of any of the fonts currently installed on the system where a WPF application is running.  In Windows 7, there are a number of fonts installed by default that can be assumed to always be present.

        <TextBlock Margin="20,20,20,0" FontSize="18" FontFamily="Candara" TextWrapping="Wrap">
            Freedom is never voluntarily given by the oppressor; it must be demanded by the oppressed.<LineBreak/>
            --Martin Luther King, Jr.
        </TextBlock>

        <TextBlock Margin="20,40,20,0" FontSize="18" FontFamily="Constantia" TextWrapping="Wrap">
            Freedom is never dear at any price. It is the breath of life. What would a man not pay for living?<LineBreak/>
            --Mohandas Gandhi
        </TextBlock>

Follow

Get every new post delivered to your Inbox.

Join 351 other followers