Showing posts with label xaml. Show all posts
Showing posts with label xaml. Show all posts

Wednesday, June 5, 2013

Keeping the Selection Color in a WPF Listbox When it Loses Focus

 

There are a lot of blog posts out there telling you to change the the ControlBrush resource of a listbox in order to maintain the selection color when the listbox item loses focus. This does not work.

If you want to set the color of the background when an item is selected, you need to change the HighlightBrush. If you want that color to persist even after the item loses focus, you need to change the InactiveSelectionHighlightBrush.

Hope this helps. Happy Coding!

 

            <ListBox.Resources>
<
SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Black"/>
<
SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="Black"/>
</
ListBox.Resources>


Wednesday, May 29, 2013

WPF Effects and Blurry Fonts

I recently ran into a very strange bug that took me a while to figure out. I noticed that several buttons in my UI had blurry text. I thought I may have mistakenly changed the opacity or had some semi-transparent gradient overlaying the font that made it look so blurry. That did not turn out to be the case. After digging around a bit I found out what was causing the problem. It turns out that the problem was in my control template. I defined the button to have a border which contains a label inside it’s content. I applied the drop shadow to the outer border and was surprised to find that applying that effect to the border caused the contents of the border to become blurry. After a little research I found that using an effect causes the elements and all the sub-elements inside the control to be rendered into a Bitmap. When this happens, WPF cannot use ClearType rendering to display the text. This causes it to look blurrier than if there is not effect applied.

Here is what my buttons looked like with the drop shadow

image

And here is the same button without the drop shadow

image

To get around this bug simply place the text outside of the control that you will be applying the effect to.

<Border>
     <Border.Effect>
          …
     </Border.Effect>
     <TextBlock Text=”Blurry Text”/>
</Border>

//Change the code above to this.

<Grid>
     <Border>
          <Border.Effect>
                …
          </Border.Effect>
     </Border>

     <TextBlock Text=”Clear Text”/>
</Grid>

If you run into this issue, just change your code like what I did above and you should have clear text on your buttons even if you are using effects.

Happy Coding.

Tuesday, April 16, 2013

Using Animated Gifs with WPF

Ever wish you could use an animated gif in your WPF application? Well, here is an easy way to do so. Simply use the WpfAnimatedGif Nuget package available on codeplex. With that library, you can easily display animated GIFs in your application via XAML or code.

Here is what the markup looks like…

 xmlns:a=http://wpfanimatedgif.codeplex.com





<Image a:ImageBehavior.AnimatedSource="Images/myImage.gif"/>


Head over to http://wpfanimatedgif.codeplex.com/ for more info.



Happy Coding!



Friday, March 29, 2013

ChangeAwareContentControl–How to know when the content changes in a ContentControl

I am working on an application where I have a ContentControl, and I need to know when the content changes. My initial thought was to add an event handler for the ContentChanged event. I came to find out that the ContentControl does not fire a ContentChanged event.

My solution was to create a control derived from content control that fires that particular event. It is working quite nicely, so I thought I would share. I hope it helps you out. It’s a small amount of code, but it does the trick.

    public class ChangeAwareContentControl : ContentControl
{
static ChangeAwareContentControl()
{
ContentProperty.OverrideMetadata(
typeof(ChangeAwareContentControl),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnContentChanged)));
}

private static void OnContentChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
ChangeAwareContentControl mcc = d as ChangeAwareContentControl;
if (mcc.ContentChanged != null)
{
DependencyPropertyChangedEventArgs args
=
new DependencyPropertyChangedEventArgs(
ContentProperty, e.OldValue, e.NewValue);
mcc.ContentChanged(mcc, args);
}
}

public event DependencyPropertyChangedEventHandler ContentChanged;
}


Here is how you use it in xaml.



<controls:ChangeAwareContentControl ContentChanged="ContenChangedHandler"/>


Tuesday, February 12, 2013

WPF- What’s Going On With My DataGrid Checkbox?

This is a very common mistake and I found myself committing it recently.

Sometimes you will find yourself wanting to create a datagrid column that contains a checkbox. The simplest way of doing this is by defining a DataGridCheckBoxColumn.

<DataGridCheckBoxColumn Binding="{Binding IsSelected}"/>


There are some situations when you might want to use a DataGridTemplateColumn instead because you want to tweak some visuals or add other controls inside the cell.


<DataGridTemplateColumn Width="30">
<
DataGridTemplateColumn.CellTemplate>
<
DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</
DataGridTemplateColumn.CellTemplate>
</
DataGridTemplateColumn>


When people do this, they sometimes find that the bindings don’t work properly. If they click on the checkbox, they notice that the property they are binding to (in this case IsSelected) does not update until you click somewhere else in the cell. Some people even miss this and just think the binding does not work at all. I ran across a case where a developer had two datagrid columns side by side, one was the DataGridCheckBoxColumn and the other one was a DataGridTemplateColumn like the ones above. The developer was convinced that something was going on because the binding was working for one and not the other.



If you run into this, don’t worry. The binding is working. It’s just not updating the bound property at the correct time. To fix this, simply make the following tweak to the binding statement. This should now cause the property to change immediately once the checkbox is checked (once the IsChecked property changes).



<DataGridTemplateColumn Width="30">
<
DataGridTemplateColumn.CellTemplate>
<
DataTemplate>
<CheckBox IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</
DataGridTemplateColumn.CellTemplate>
</
DataGridTemplateColumn>


That’s it. Hope this helps.

Happy Coding!



Thursday, February 7, 2013

WPF Tooltip

Adding a tooltip to a control in WPF is pretty simple. Here is the basic syntax.
<Button Content="Button" ToolTip="This is a tooltip"/> 


image


There are various properties that can be adjusted to tweak the behavior of the tooltip. This is done via the TooltipService attached property.


<Button Content="Button" ToolTip="This is a tooltip"
                ToolTipService.HasDropShadow="False">
            
</Button>


The properties that can be tweaked on the TooltipService are:

BetweenShowDelay This value specifies how much time (in milliseconds) the user has to move from the control that is displaying the tooltip to another one without having to wait for it’s InitialShowDelay. Essentially, if I set this value to X, once I see the tooltip on my control, I have X milliseconds to hover over another control that has a tooltip and that other tooltip will show up immediately.
 
HasDropShadow Specifies if the tooltip has a dropshadow.
 
HorizontalOffset Offset from the left of the area that is specifies for the tooltip.
 
InitialShowDelay How long it takes for the tooltip to open (in milliseconds).
 
IsEnabled Determines whether the tooltip gets displayed.
 
IsOpen Gets whether the tooltip is open.
 
Placement Sets the orientation of the tooltip when it opens
 
PlacementRectangle Gets or sets the rectangle area in which the tooltip is displayed
 
ShowDuration Specifies the amount of time the tooltip is displayed
 
ShowOnDisabled Specifies if the tooltip is displayed when the parent object is disabled
 
ToolTip Gets or sets the content of the tooltip
 

VerticalOffset
Offset from the top of the area that is specifies for the tooltip.



You can any visual element as the content of a tooltip by defining in a nested element rather than an attribute.


        <Button Content="Button">            
            <ToolTipService.ToolTip>
                <Rectangle Fill="Red" Height="20" Width="20"/>
            </ToolTipService.ToolTip>
        </Button>



image


Happy Tooltiping!


Tuesday, February 5, 2013

The Basics: Intro to Windows Presentation Foundation

I have spoken to several developers this week who have heard of WPF, but have no experience with it. I have been working with this technology for so long, that I take it for granted. I decided to write a few blog posts specifically for those developers that are just starting out with WPF.
The Links First, here are a few useful links to get you started
http://www.microsoft.com/expression/
download Microsoft Expression Blend
http://www.microsoft.com/visualstudio/eng/products/visual-studio-overview 
go to express products to download the free version of Visual Studio
This is by far the Best book for learning WPF. I highly recommend it

Introduction Now that I've used the term WPF several times, I should probably give a formal definition for it. As seen in the title of this blog post, WPF stands for Windows Presentation Foundation. So why use WPF when there are other options like Windows Forms out there? While there are many opinions out there, I believe the biggest benefit to using WPF is that it provides a clear separation between the application behavior and the user interface. Rather than defining the user interface in code like VB or C#, WPF introduces xaml (eXtensible Application Markup Language). This xml markup is used to define the user interface. When an application is built, the compiler reads the xaml (pronounced zammel) markup and generates the appropriate objects to construct the user interface.
Everything you can do in xaml you can do in code. You can create a WPF application without writing a single line of xaml, but that is not common. Declaring your user interface in xaml provides a cleaner separation between the look of the application and the behavior of the application. It also allows you to use the design tools (like Expression Blend) available for creating complex user interfaces. Also, xaml is much easier to read and a lot shorter than code.
C# / Xaml Comparison
The following xaml and c# code both produce the same result – the following interface.
image
xaml
    <Grid>        
        <StackPanel>
            <Label Content="My First WPF App"/>
            <Button Content="Hello World"/>
            <TextBox/>            
        </StackPanel>
    </Grid>

C#
            Grid g = new Grid();
            StackPanel s = new StackPanel();

            Label l = new Label();
            l.Content = "My First WPF App";

            Button b = new Button();
            b.Content = "Hello World";

            TextBox t = new TextBox();

            //populate stack panel
            s.Children.Add(l);
            s.Children.Add(b);
            s.Children.Add(t);            

            //add stackpanel to grid
            g.Children.Add(s);

            //set application content
            this.Content = g;

From this small example you can clearly see that the C# code is much longer and more difficult to read than the equivalent xaml markup.

Xaml Basics

To initialize an object simply create a new xml element.

             <StackPanel/>
        <
Button
/>
        <
Label
/>
        <
TextBlock
/>
        <
TextBox
/>
        <
ListBox/>
 
         . . .
   
There are two ways of adding properties to elements:

1)Inline
             <StackPanel Orientation="Horizontal" Margin="2"/>   
        <
Button Content="Click Me" Height="50" Width
="100"/>
        <
Label Content
="Hi"/>
        <
TextBox Text
="Enter text here"/>
        <
ListBox Height="300"/>


or

2) As nested elements. This allows building more complex elements.
        <Button Height="50" Width="100">
            <StackPanel Orientation="Horizontal">
                <Label Content="Click"/>
                <Image Source="click_here.png"/>
            </StackPanel>
        </Button>


The Visual Tree
WPF introduces the notion of a visual tree and a logical tree. It is important to understand the difference between the two.

When building a user interface, one can talk about the different elements that make up the interface. That is what is referred to as the logical tree.

    <Grid>
        <Button/>
    </Grid>

The logical tree for this code is represented as
image

The visual tree refers to the various visual elements that make up a logical element. The logical tree just for the button above is represented as:

image

This specifies, in great detail, how the button control is visually constructed. WPF gives developers the flexibility to completely redefine visual tree of any given control. This is done via Styles and Templates.

Styles and Templates
Here is where WPF development, in my opinion, really shines. Styles can be used to make reusable chunks of code that define visual properties of specific UI elements or a certain type of element. They are very similar to Cascading Style Sheets in web development. With styles, you can easily define the look for all the buttons within a given application as a single style and apply it globally.style

Below I define 4 styles for Label controls. The first is the default style for all labels within scope. If a label is created within the scope of this style and no style is defined, it will pick up the properties defined by this style. Default styles are created in WPF by simply creating a style without giving it a Key (style identifier).

                <Style TargetType="{x:Type Label}">
                    <Style.Setters>
                        <Setter Property="Foreground" Value="Red"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                        <Setter Property="FontSize" Value="40"/>
                    </Style.Setters>
                </Style>

                <Style TargetType="{x:Type Label}" x:Key="BigBlueStyle">
                    <Style.Setters>
                        <Setter Property="Foreground" Value="Blue"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                        <Setter Property="FontSize" Value="40"/>
                    </Style.Setters>
                </Style>

                <Style TargetType="{x:Type Label}" x:Key="LittleGreenStyle">
                    <Style.Setters>
                        <Setter Property="Foreground" Value="Green"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                        <Setter Property="FontSize" Value="10"/>
                    </Style.Setters>
                </Style>


The second and third styles both have Keys. In order to use this style, the label must set the Style attribute using the following syntax.

        <StackPanel>
            <Label Content="First Label"/>
            <Label Content="Second Label" Style="{DynamicResource BigBlueStyle}"/>
            <Label Content="Third Label" Style="{DynamicResource LittleGreenStyle}"/>
            <Label Content="Fourth Label" Foreground="Purple"/>
        </StackPanel>

The product of this code looks like this:

image

Notice how the fourth label overrides the foreground color to purple.

Templates are a bit different from styles. While styles allow you to set properties, templates allow you to redefine the visual tree of an element. There are two different kinds of templates used in WPF

1)Datatemplate – Used for describing how data should be displayed. This type of template is commonly used in list-based controls like listboxes or comboboxes.

2)ControlTemplate – Used for describing the appearance of a control.

Simple example:

In this example I change the visual tree of the button. This defines the button to be made up of a green grid with an inner stackpanel that has a textblock, a rectangle and a combobox. Note, the user can still interact with any of the elements inside the button like the combobox. This, in my opinion, is the single most powerful feature in WPF. Developers are completely free to redefine visual elements in inumerable ways to meet their needs.

       <Button Height="100" Width="200">
            <Button.Template>
                <ControlTemplate>
                    <Grid Background="Green">
                        <StackPanel  VerticalAlignment="Center"> 
                            <TextBlock Text="Click Me"/>
                            <Rectangle Fill="Black" Height="30" />
                            <ComboBox>
                                <ComboBox.Items>
                                    <ComboBoxItem Content="Item One"/>
                                    <ComboBoxItem Content="Item Two"/>
                                    <ComboBoxItem Content="Item Three"/>
                                </ComboBox.Items>
                            </ComboBox>
                        </StackPanel>                        
                    </Grid>
                </ControlTemplate>
            </Button.Template>
        </Button>
imageimage

This has only been a quick intro to WPF. I hope it’s been helpful to understand the basics of this technology. Please take a look around this blog to find other articles related to wpf development.

Happy Coding!

Friday, August 24, 2012

How to Change Application FontFamily at Runtime

This one stumped me for a while. There are a lot of blog posts out there on how to change the font family of a particular style if you know the key, or how to do it for all textblocks in the application. The problem I was facing was that I used a lot of Labels and other controls that did not pick up these changes. Not only that, but I found no way of editing my default styles at runtime. After trying several approaches, I came up with this solution. I don’t know if it will work for everyone, but in my case, it is working beautifully. I hope it helps.


        private void applyFontFamilySettings()
        {
            foreach (DictionaryEntry entry in Application.Current.Resources)
            {
                if (entry.Value is Style)
                {
                    Style originalStyle = (Style)entry.Value;
                    swapStyles(originalStyle, entry.Key, originalStyle.TargetType);
                }
            }
        }

        private void swapStyles(Style s, object styleKey, Type t)
        {
            Style newStyle = new System.Windows.Style()
            {
                TargetType = t
            };

            foreach (Setter st in s.Setters)
            {
                newStyle.Setters.Add(st);
            }

            newStyle.Setters.Add(new Setter(FontFamilyProperty, UiSettings.FontFamily));
            Application.Current.Resources[styleKey] = newStyle;
        }




Thursday, February 2, 2012

Expression Blend Bug–Can’t Open UserControl

Ever seen this when trying to work in Blend?

(Element Name) is not supported in a windows presentation foundation (WPF) project.

or this?

(UserControl) is not supported in a windows presentation foundation (WPF) project.

Well, I ran into this and had a tough time figuring out what was going on. There are a lot of forum posts out there talking about the topic, but no real solution that I have found. I kept on trying different things and was able to overcome it. Here is what I did to fix it.

I went to the solution explorer in visual studio and right clicked on the project file for the project that was having the problems. I selected ‘Edit Project File’. This unloads the project from the current solution and opens the project file in the xml editor.

Towards the top of the file you should see something like this

image

After my offending project file with other functioning project files, I noticed that my platform was set to x86 rather than AnyCPU like my other projects. I changed it to AnyCPU, saved, reloaded the project, built the solution and then tried to open the UserControl in Blend. This fixed the problem!

If you are having this same issue, I’d give that a shot. Good luck!

Monday, November 28, 2011

How to Create a Simple Splash Screen in WPF

I have posted on this topic before, but I thought I would re-post with a step by step tutorial for those who are very new to wpf. Sorry to those of you who are more veterans. I will post more advanced topics soon, but this one’s for the newbies.

Here goes…

WPF makes creating a splash screen fairly simple. All you need to do is embed an image file into your project and change the Build Action on it.

Here is a step-by-step tutorial on how to do this.

Step 1) Create your application.
Here is the xaml for my very complicated application:

image

Step 2) Add an image file to your application. PNG files with transparent backgrounds are supported and are often a good choice for splash screens. Here is the image I created in Photoshop… nice huh?

image

Step 3) Right click on the image file in the solution explorer and click on Properties

image

Step 4) Set the Build Action to SplashScreen in the Properties panel

image

Step 5) Build and run the application.

 

You should now see your image splash before the application is loaded. I managed to get a screenshot as the splash screen was fading out and my application was starting to fade in.

image

That’s all there is to it. It is very simple. There are other ways to show and hide your splashcreen in code, but I won’t get into that in this post. I just wanted to keep it simple for those of you new to SplashScreens in wpf. Happy Splash Screening!

Friday, October 7, 2011

Wpf and the invisible checkbox (and radio button)

Just ran into another strange wpf bug. This one involves checkboxes and radiobuttons. I was working on a login screen that has a couple of checkboxes for remembering the username and password. The code looked like this…

<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
     <
CheckBox Content="Username" Foreground="White"/>
     <CheckBox Content="Password" Foreground="White"/>
</StackPanel>

These checboxes were on a dark colored panel, so the white text showed up nicely. Running the app on my Windows 7 box worked fine, but when I ran the app on a Windows XP box, you could not see the check mark inside the box when the user clicked on it. The control still worked, but the check was just invisible. Actually, it wasn’t invisible, it was just a white checkmark on a white box (aka… invisible). This is a wpf/windows xp/checkbox bug. In Windows XP, when the foreground color is changed, the checkmark picks up that color change… why? you ask?… I don’t know. But, here is a workaround for this situation. Simply put labels with the white foreground as the content for your checkboxes. Now the foreground color of the checkbox is still the default (black) color and the checkmark will be visible for those running the app in Windows XP. Here is the modified code.

<StackPanel HorizontalAlignment="Left"  Orientation="Horizontal">
<
CheckBox>
<
Label Content="Username" Foreground="White"/>
</
CheckBox>
<CheckBox>
<Label Content="Password" Foreground="White"/>
</CheckBox>
</StackPanel>



I have also seen this issue with radiobuttons. Use the same workaround for that and you should be good to go.



I hope this helps. If it does, feel free to leave a comment. Thanks!



Wednesday, December 15, 2010

WPF VisualStateManager GotoState Bug

So, I just wasted a couple of hours trying to figure this one out so I thought I’d post about it so you guys don’t have to waste as much time as I did on it.

The WPF VisualStateManager implementation is still not as rock solid as Silverlight’s implementation (ok, let’s face it, Silverlight’s implementation is far from rock solid too, but it is much better of at this point). If you are trying to call the VisualStateManager.GotoState Method on a Window, you are going to be very very frustrated. Why? Because it doesn’t work. If you are inside a user control, it is fine, but inside of a Window… nope!

Instead of calling this

VisualStateManager.GoToState(this, "stateName", true);


You are going to need to call this



VisualStateManager.GoToElementState(this.RootElement as FrameworkElement, "stateName", true);


That should do it for you. Microsoft is aware of the issue and has promised to fix this, but who knows when that’s going to happen.



Happy state-changing!



 




WPF - Accessing Resource Dictionaries in Separate Assemblies

There are certain situations where you will need to access resource dictionaries outside of your application. For example, you may want to share one resource dictionary among several applications that share the same styles.

What you want to do is use WPF’s pack URI Scheme.

Remember to include a reference of the assembly containing the resource dictionary (YourAssembly) in the application project. Then, all you have to do is use this rather strange looking syntax to access that resource dictionary within your xaml.

<ResourceDictionary Source="pack://application:,,,/YourAssembly;component/Subfolder/YourResourceDictionary.xaml"/> 

There are many variations of this syntax that you can use. Which one is right for you depends on exactly what you are trying to do. The above syntax should work for a majority of the situations. Accessing these resources can be done in both xaml and the code behind.

For more information on the pack URI Scheme syntax, follow this link:

http://msdn.microsoft.com/en-us/library/aa970069(v=vs.85).aspx

Note - this syntax is not only for resource dictionaries. This is useful for accessing several types of data files like images for example. This is commonly used for accessing resource dictionaries, but it is not limited to that.

 

Wednesday, May 20, 2009

How to Create a Sivlerlight Fly Out Panel

-Note: This example is built on Silverlight 2.0

clip_image002

clip_image004

Description:

Using fly out panels is a good way to add a touch of animation to applications while also increasing the amount of available browser real estate. In this post, I will show you how to create a basic fly out panel using Expression Blend and minimal C# code. The progression depicted in the images above begins with the panel will out of view except for its right border. When the border is clicked, the panel will fly into view. Clicking the panel again causes the panel to return to its hidden position.

Level of Difficulty: clip_image006 Easy

Preparation/Directions:

1. Create a New Silverlight application in Blend and name it FlyOutPanelBlend.

2. Set the Height and Width of the UserControl to Auto

a. Open Page.xaml by double clicking on it on the Project tab.

b. Select the [UserControl] node on the Objects and Timeline panel.

c. In the Properties tab, go to the Layout section and Change the Width and Height properties from their defaults, 640 and 480, to Auto.
clip_image008

This can be done by either typing the “Auto” in the appropriate textboxes, or by clicking the Set to Auto button clip_image009 to the right of each textbox.

3. After setting the Width and Height to Auto, the UserControl will be too small for laying out the user interface using the designer in Blend. To fix this, change the design time Height and Width properties of the UserControl.

a. Select the [UserControl] node on the Objects and Timeline panel.

b. Three extra handles are displayed around the UserControl, one on the bottom, one on the right, and one on the bottom right hand corner. These are used to click and drag in order to modify the design time Width and Height of the UserControl. Click and drag the triangle handle on the bottom right hand corner down and to the right. Notice that as you drag small labels display the values for the design time Height and Width.

clip_image011

c. To modify these values with greater accuracy, click on the Split view to show the designer and the XAML code simultaneously.
clip_image013

d. When dragging the handles for the design time Width and Height, Blend adds several extra attributes to the UserControl element telling it to display the user control in design time at the appropriate Width and Height. Change the d:DesignWidth value to 1024 and the d:DesignHeight property to 768. Note: The XAML show below has been formatted for easier reading.
clip_image015

e. Set the background color of the main grid by selecting the grid LayoutRoot on the Objects and Timeline panel. In the Properties tab, select the Background property and set it to a solid color brush by selecting the second sub-tab (Solid color brush), and choosing black from the color picker.

clip_image017

f. Right click on the Grid icon clip_image019 on the toolbox to show other panel control options. Select Border from the list to hide options. The Grid icon has now been replaced with the Border icon. Double click on the Border icon to place a Border object inside the LayoutRoot grid.
clip_image021

g. Set the background color of the border and name it bdrMenu by selecting the border on the Objects and Timeline panel. In the Properties tab, set the Name property to bdrMenu and select the Background property and set it to a solid color brush by selecting the second sub-tab (Solid color brush), and choosing white from the color picker.

h. Now stretch the border vertically to fill the entire height of the window. Do this by going to the Layout panel in the Properties tab and setting the Height property to Auto clip_image009[1] and the VerticalAlignment property to Stretch.

clip_image023

i. Change the width of the border to 200 and give it rounded corners on the tob and bottom right corners by setting the CornerRadius to “0,10,0,10” (top left, top right, bottom left, bottom right).

j. Place a title on top of the menu by double clicking on the TextBlock icon clip_image025 in the toolbox. This will place a textblock inside bdrMenu. If a TextBlock does not appear inside the Border, undo the last action (Ctrl+Z) and make sure the bdrMenu was selected in the Objects and Timeline panel before double clicking the TextBlock icon.

k. In the Properties panel, give the TextBlock the following properties: Text=”Menu”, FontSize=”22”, HorizontalAlignment=”Center”, and VerticalAlignment=”Top”.

l. Move the menu almost entirely off the screen, leaving the right border visible. To do this, select bdrMenu on the Objects and Timeline panel. Then, Properties tab, go to the Transform panel and set the value next to the X to -180. This will give the border a TranslateTransform with a value of -180 for the X property.
clip_image027

m. Create a new Storyboard for animating the panel into view. In the Objects and Timeline panel, click the New Storyboard buttonclip_image029 and name it ShowPanel.

clip_image031

n. You will see a timeline appear. Drag the yellow line to .5 seconds and select bdMenu on the Objects and Timeline panel.

o. Set the TranslateTransform’s X value to 0 in the Translate panel of the Properties tab. This will cause the panel to be visible after half a second whenever the storyboard is played. When making this change, you should see the property recorded in the timeline with a little sphere on the .5 marker. If you wish to make the animation take longer or shorter than .5 seconds, simply drag it left or right accordingly.

clip_image033

p. Expand the dropdown menu by the New Storyboard button by clicking the
triangle and select Duplicate.
clip_image035

q. This will create a copy of the previously created storyboard. Expand this same menu again and choose Reverse. Expand the menu once again and choose Rename. Rename the storyboard to HidePanel.
Generated Xaml
clip_image037

4. Open Page.xaml.cs in Visual Studio and add an AddEventHandlers method in the constructor. In the implementation of AddEventHandlers, assign a new event handler to the MouseLeftButtonDown event of bdrMenu.

5. Add a private member variable of type bool named _hidden. This will be used to keep track of the state of the panel. If the panel is hidden, this value will be set to true, otherwise it will be set to false.

6. In the event handler, create a conditional statement. If _hidden is true, begin the ShowPanel storyboard and set the _hidden flag to false. Conversely, if _hidden is false, begin the HidePanel storyboard and set the _hidden flag to true.

7. Finally, clean up the unnecessary using statements from the top of the file only keeping using System.Windows.Controls; and using System.Windows.Input;.

clip_image039

Wednesday, July 16, 2008

WPF and Silverlight Best Practice: Event Handlers


When developing WPF and Silverlight applications, developers and designers can create a clean line of separation between the look and feel of the application and its functionality. This is possible because of XAML. Although it is possible to create WPF or Silverlight applications entirely of procedural code (VB or C#), it is highly unlikely you would see such an application. Typically, designers work on the XAML files while developers work on the code behind files. In the XAML files, designers can specify what the UI looks like, while developers deal with the behavior. It is possible, however, for designers to embed some basic functionality within the XAML itself. One example is in defining event handlers. In the following code snippet I am defining a button.

<Button x:Name="btnSave" Content="Save" Width="90" Height="25" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="118,0,0,11.33899974823" Click="MyClickHandler"/>

This button has various properties that define its look and feel including Content, Width, Height, etc. I have also specified an event handler for the button's Click event. The body of this even handler is found in the code behind file of my Silverlight or WPF control. This code is perfectly legitimate. In fact, it can clean up your code behind files significantly. If you have 50 buttons, each of which need to point to this event handler, it removes a lot of these statements.


btnSave.Click += new RoutedEventHandler(MyClickHandler);

This was my reasoning when I first started writing WPF apps. I thought I would clean up my .cs files as much as possible. If I could write it in XAML, I would. There is a small problem with this approach. Lets say the XAML snipped above was found in a xaml file that was then handed off to a designer. The designer opens it up in a design tool like Expression Blend and decides the button looks terrible with all those attributes. Instead, he/she wants the button to look a lot different, so he/she decides to completely wipe out that button and start from scratch. As long as there is a button named btnSave, the application should build. So, he/she ends up with this

<Button x:Name="btnSave" Content="Click to Save" Style="{StaticResource SaveButtonStyle}" Margin="0,4.5,2,0" VerticalAlignment="Top" d:LayoutOverrides="Height"/>

This button now has a completely different look and feel. It points to a style resource which may drastically change the appearance of the button. At this point the designer builds the application and there are no errors, so he/she is happy. There have been no breaking changes and the button looks great…. WRONG! Although the application builds and it looks great, there has been a major change in the behavior of the button. With the following code, there is no handler for the click event. The designer accidentally wiped out the old XAML not realizing that a little bit of functionality had been defined there. This is the problem with defining event handlers inside XAML code.

As a best practice… Always assign your event handlers in your procedural code. Here is what I do… Inside the constructor of all my WPF and Silverlight controls, I add a method called AddEventHandlers(). Inside this method, I take care of adding the event handler to all my controls defined in my XAML. The code looks something like this:


public MyControl()

{

InitializeComponent();

AddEventHandlers();

}

private void AddEventHandlers()

{

btnSave.Click += new RoutedEventHandler(MySaveClickHandler);

btnExit.Click += new RoutedEventHandler(MyExitClickHandler);

btnOk.Click += new RoutedEventHandler(MyOkClickHandler);

}