Compartilhar via


Try it: Create a custom WPF control

This page applies to WPF projects only

Microsoft Expression Blend provides a number of different system controls and simple styles that you can use in your Windows Presentation Foundation (WPF) applications. However, if these controls or styles do not meet a specific need that you have, you can create a custom control, by creating a Microsoft .NET class that inherits from one of the System.Windows.Controls classes.

Note

This topic contains information for Windows Presentation Foundation applications. For information about Microsoft Silverlight 1.0, see Overview of Silverlight 1.0 and the Silverlight learning center. Also see the Silverlight 1.0 samples that come with Expression Blend 2, some of which use JavaScript classes to define reusable objects. On the Help menu, click Welcome Screen, and then select the Samples tab. The MagnifyingGlass, ButtonGallery, and BlendPlayer samples are Silverlight 1.0 samples.

The following procedures show you how to create a custom button control that includes a new property to hold the path of an image file in order to display an image. (For an example of creating a user control without using code, and therefore has no custom properties, see Try it: Create a WPF user control.)

For more information about custom controls, including XAML and code examples, see Control Authoring Overview and DependencyProperty Class in the Windows Presentation Foundation section on MSDN.

To define a custom control

  1. In the Project panel, locate the file Window1.xaml and expand it to reveal your project’s code-behind file, which is named Window1.xaml.cs. (If you chose Microsoft Visual Basic as the language when you created your project, the code-behind file will be named Window1.xaml.vb.) Double-click the code-behind file to open it for editing.

    Note

    The code-behind file will open in Microsoft Visual Studio 2008 if it is installed. Otherwise, the code-behind file will open in the application that is mapped to the file extension of the code-behind file. For example, if you have opened a .cs or .vb file in Notepad, Expression Blend will open the file in Notepad. For help opening code-behind files, see Edit a code-behind file.

  2. In the Window1.xaml.cs file, paste the following class definition source code just before the last closing brace (}) in the file. (For Visual Basic, paste the appropriate code just before End Namespace or just after the last End Class.)

    public class ImageButton : Button 
    { 
      public ImageSource Source 
      { 
        get { return base.GetValue(SourceProperty) as ImageSource; } 
        set { base.SetValue(SourceProperty, value); } 
      } 
      public static readonly DependencyProperty SourceProperty = 
        DependencyProperty.Register("Source", typeof(ImageSource), typeof(ImageButton)); 
    }
    
    Class ImageButton
      Inherits Button
      Public Property Source() As ImageSource
        Get
          Return CType(MyBase.GetValue(SourceProperty), ImageSource)
        End Get
        Set(ByVal value As ImageSource)
          MyBase.SetValue(SourceProperty, value)
        End Set
      End Property
      Public Shared ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register("Source", GetType(ImageSource), GetType(ImageButton))
    End Class
    
  3. Save the modified code-behind file, and then close Visual Studio or whatever application you used to edit the file.

    Tip

    The ImageButton class demonstrates the dependency property pattern. Externally, the class exposes a regular common language runtime (CLR, that is, .NET) property named Source, which is of type ImageSource. The class also registers and exposes a read-only dependency property field named SourceProperty, and implements the CLR accessors for the Source property in terms of the dependency property. Backing a CLR property with a registered dependency property means that WPF can provide a wealth of services to your property. These services include styling, data binding, value inheritance, default values, and animation. There is also a feature in WPF called template-binding where you bind to the property's value from within a control template. This tutorial will show template-binding in action.

    Tip

    If you prefer to keep your custom control class definition source code in a separate source code file, you can do so. As an alternative to the previous two steps, if you prefer, you can create a new file called ImageButton.cs, paste the source code into this file together with the namespace declaration and the same set of using directives from your document’s code-behind file, and then add the new file to your project (on the Project menu, click Add Item).

  4. You now need to build your project so that the new ImageButton control will appear in the Asset Library. On the Project menu of Expression Blend, click Build Project (or press CTRL+SHIFT+B). Verify that the build has completed without errors.

  5. Switch back to editing Window1.xaml in Expression Blend.

  6. In the Toolbox along the left side of Expression Blend, click the Asset Library button Cc295235.0224cabd-5da1-4e01-bddd-4a647401a098(en-us,Expression.10).png.

    This opens the Asset Library to show you all of the controls, panels, and elements that you can place in your document.

  7. From the Custom Controls tab, select the ImageButton control from the list.

    The Toolbox icon above the Asset Library button is now set to your ImageButton control, and it is already selected so that you can draw the control on the artboard.

    Note

    Custom controls will not appear in the Custom Controls tab of the Asset Library unless you have added the source code to your project and performed a build (CTRL+SHIFT+B).

  8. With the ImageButton icon selected in the Toolbox, draw an ImageButton by clicking on the artboard and drawing a bounding box inside the document.

    The ImageButton is rendered on the artboard and an ImageButton element named [ImageButton] "ImageButton" is listed as a child element of LayoutRoot under Objects and Timeline in the Interaction panel.

Cc295235.7e183f1f-37d8-4dcb-980c-19a5d61ca087(en-us,Expression.10).gifBack to top

To modify the style of your custom control

  1. To create a control template for all ImageButton elements, right-click the new ImageButton, click Edit Control Parts (Template), and then click Edit a Copy.

    The Create Style Resource dialog box appears.

  2. In the Resource name (Key) field of the Create Style Resource dialog box, in the text box next to the first radio button, type ImageButtonStyle.

    This sets a name for your template in the resource dictionary so you can set it as the template for any ImageButton element.

    Note

    Control templates are wrapped inside styles so that the style that is applied to a control includes both the appearance (parts) and the behavior for the control.

  3. In the Define in field, select the This document radio button and make sure that Window: Window is selected in the drop-down list.

    The Define in field indicates which resource dictionary to define your new template in. Selecting Window: Window means that the template will be visible to all ImageButton controls in the window.

  4. Click OK.

    You have now copied the default control template of all ImageButton elements and have saved the copy as a new ControlTemplate named ImageButtonStyle. The new template has been placed in the resource dictionary, which you can view in the Window node of the Resources panel.

    With the creation of a new template, Expression Blend enters a mode in which you can view and edit the new template. Under Objects and Timeline in the Interaction panel, the word Template above the new element tree indicates the current scope in which you are editing. The template includes a ContentPresenter element that will automatically display the value of the Content property of the ImageButton that uses this template.

    Tip

    To exit the template-editing mode and return to the scope of your document, click the Scope Up button Cc295235.55844eb3-ed98-4f20-aa66-a6f5b23eeb2b(en-us,Expression.10).png, which is above the element tree next to the word ImageButtonStyle.

    To return to template editing mode for an existing template, right-click the element whose template you want to edit under Objects and Timeline in the Interaction panel (in this case, the [ImageButton] "ImageButton" element), click Edit Control Parts (Template), and then click Edit Template.

  5. Under Objects and Timeline, right-click the ContentPresenter object, point to Group Into, and then click Grid.

    The ContentPresenter object is made a child element of a new Grid object. Without the grid object, you would not be able to add a second child element to the template because the chrome object can only contain one child element.

  6. With the Grid object selected under Objects and Timeline, locate the Width and Height properties in the Layout category of the Properties panel. Click the Advanced property options Cc295235.d6ba8f4a-b8a2-445a-af0b-a267dfade6e1(en-us,Expression.10).png button beside each of the properties and click Reset.

  7. To divide the grid into two columns, double-click the grid object under Objects and Timeline to activate the grid, and then with the Selection tool Cc295235.2ff91340-477e-4efa-a0f7-af20851e4daa(en-us,Expression.10).png selected in the Toolbox, move the mouse pointer over the thick blue ruler area at the top of the Grid on the artboard. An orange column ruler will follow your mouse pointer to indicate where a new column divider will be placed if you click.

    Click to create a new column divider in the middle of the Grid.

    A blue column divider appears inside the Grid.

  8. Select the Image tool Cc295235.0594f05b-2193-4385-86a0-2d352cacfe55(en-us,Expression.10).png from the Controls tab of the Asset Library (select the Show All checkbox). With the Grid element still activated under Objects and Timeline in the Interaction panel, draw a new Image inside the right column of the Grid.

  9. With the new Image element selected under Objects and Timeline, look under Common Properties in the Properties panel. Click the Advanced property options Cc295235.d6ba8f4a-b8a2-445a-af0b-a267dfade6e1(en-us,Expression.10).png button to the right of the Source property, point to Template Binding, and then click Source.

    You have just template-bound the Source property of the Image to the Source property of the ImageButton that uses this template.

  10. You are now done editing the template. To exit to the scope of the root element, click ScopeUp under ObjectsandTimeline.

  11. With your ImageButton selected under ObjectsandTimeline, locate the Source property in the Miscellaneous category of the Properties panel, and set it to the path of an image file on your computer.

    The image displays on the right side of the ImageButton control.

Cc295235.7e183f1f-37d8-4dcb-980c-19a5d61ca087(en-us,Expression.10).gifBack to top

To apply the style to another custom control

  1. From the CustomControls tab of the AssetLibrary, select the ImageButton control. Draw a new ImageButton control on the artboard.

  2. Right-click the new ImageButton, click Edit Control Parts (Template), click Apply Resource, and then click the name of your style, ImageButtonStyle.

    The ImageButtonStyle is applied to your new ImageButton control. Locate the Source property in the Miscellaneous category of the Properties panel, and set it to the path of an image file on your computer.

    Note

    Alternatively, you could add an ImageButton to the artboard that is already styled using your template. From the Local Styles tab of the Asset Library, select ImageButtonStyle, and then draw the styled ImageButton on the artboard.

Cc295235.7e183f1f-37d8-4dcb-980c-19a5d61ca087(en-us,Expression.10).gifBack to top

Advanced: Apply descriptions for your custom property

  1. In the top of the code-behind file (Window1.xaml.cs), add a reference to the System.ComponentModel namespace.

    The Description and Category attributes used below are defined in that namespace.

  2. Paste the following line (bolded) before the class definition:

    [Description("Represents a custom button control that responds to a Click event. Displays an image using a custom Source property if the Source property is bound to an Image in the template.")]
    public class ImageButton : Button
    
    <Description("Represents a custom button control that responds to a Click event. Displays an image using a custom Source property if the Source property is bound to an Image in the template.")> _
    Class ImageButton
    
  3. Paste the following line (bolded) before the custom property definition:

    [Description("The image displayed in the button if there is an Image control in the template whose Source property is template-bound to the ImageButton Source property."), Category("Common Properties")] 
        public ImageSource Source
    
    <Description("The image displayed in the button if there is an Image control in the template whose Source property is template-bound to the ImageButton Source property."), Category("Common Properties")> _ 
        Public Property Source() As ImageSource
    

    The Category attribute configures where the property will show up in the Properties panel.

  4. Rebuild your project (CTRL+SHIFT+B).

    Now, the Source property for the ImageButton appears in the Common Properties category of the Properties panel, and the descriptions appear in tooltips when you move your mouse pointer over the property and over the control in the Asset Library.

Cc295235.7e183f1f-37d8-4dcb-980c-19a5d61ca087(en-us,Expression.10).gifBack to top

Advanced: Configure your control to display a default image

You can add code to the constructor of any custom control that will set a property to a default value when your control is drawn on the artboard, and therefore in design mode. Setting a property using the following procedure will only affect what you see on the artboard and will not affect what you see when your application is running. This is useful when content is not available for your control when in design mode, but will be available when your application is running, such as when the content comes from a database or Web service. In this case, the Source property of an ImageButton on the artboard is set to the name of an image file in your project until it is explicitly set.

  1. In the code-behind file (Window1.xaml.cs), paste the following lines of code (bolded) after the property definition:

    Note

    Change the file name (Sunset.jpg) in the following code to the name of an image file in your project. To add an image file to your project, right-click your project name under Files in the Project panel, and click Add Existing Item.

    public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(ImageButton));
    
    // Constructor:public ImageButton(){   if (DesignerProperties.GetIsInDesignMode(this))   {      this.Source = new BitmapImage(new Uri("Sunset.jpg", UriKind.Relative));   }}
    
    Public Shared ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register("Source", GetType(ImageSource), GetType(ImageButton))
    
    Public Sub New()    If DesignerProperties.GetIsInDesignMode(Me) Then        Me.Source = New BitmapImage(New Uri("Sunset.jpg", UriKind.Relative))    End IfEnd Sub
    
  2. Rebuild your project (CTRL+SHIFT+B).

    Now, when you add an ImageButton to the artboard that uses the style that you created, a default image appears in the button.

    Note

    You will not be able to set the Source property to any other value while in design mode.

Cc295235.7e183f1f-37d8-4dcb-980c-19a5d61ca087(en-us,Expression.10).gifBack to top