Archive

Posts Tagged ‘WPF Custom Control’

WPF Custom Control

August 12, 2012 2 comments

The differences between CustomControls and UserControls

WPF has two concepts of controls: UserControls and CustomControls. But what’s the difference between them? In this article I try to list the characteristics of each of them to help you to choose the right type for your project.

UserControl (Composition)

  • Composes multiple existing controls into a reusable “group”
  • Consists of a XAML and a code behind file
  • Cannot be styled/templated
  • Derives from UserControl

This example of an “RGB user control” composes three labels and textboxes as well as a color field together to an reusable part. The logic in the code behind file adds a Color DependencyProperty that gets and sets the resolved color.

CustomControl (Extending an existing control)

  • Extends an existing control with additional features
  • Consists of a code file and a default style in Themes/Generic.xaml
  • Can be styled/templated
  • The best approach to build a control library

This example of a “Numeric up/down” control is an extension of a textbox. The up and down buttons are defined in the default template of the control and wired up in the OnApplyTemplate() override in the logic part of the control. The ControlTemplate can easily be exchanged by another that has the up,down buttons aligned left for example.

How to Create a WPF Custom Control

Step 1: Open VS 2010 and create a blank solution and  name it as ‘WPF_CustomControl’..

Step 2: To this solution, add a new WPF Custom Control Library Project and name it as ‘WPF40_FileUploadCustomControl’. This project will have ‘Themes’ folder containing ‘Generic.Xaml’. Also this project will contain ‘CustomControl1.cs’ code file. This file will contain necessary business logic of the control.

Step 3: Rename ‘CustomControl1.cs’ to ‘FileUploadCustomControl.cs’. Add the following code in ‘Generic.xaml’:

<ResourceDictionary

    xmlns:local=”clr-namespace:WPF40_FileUploadCustomControl”>
    <Style TargetType=”{x:Type local:FileUploadCustomControl}”>
        <Setter Property=”Template”>
            <Setter.Value>
                <ControlTemplate TargetType=”{x:Type local:FileUploadCustomControl}”>
                    <Border Background=”{TemplateBinding Background}”
                            BorderBrush=”{TemplateBinding BorderBrush}”
                            BorderThickness=”{TemplateBinding BorderThickness}”>
                        <StackPanel Orientation=”Horizontal”
                                          Width=”200″>
                            <TextBox Name=”TXT_FILE_NAME” Width=”150″></TextBox>
                            <Button Name=”BTN_BROWSE_FILE” Width=”50″Content=”Browse”></Button>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
The above code defines only the control template which contains ‘StackPanel’, ‘TextBox’ and ‘Button’ visual elements. One important here is that since this is just a resource dictionary, you cannot define any event on the elements.
 –
Step 4: Now it’s time to define the business logic. Make sure that in the ‘FileUploadCustomControl.cs’ file, the class ‘CustomControl1’ is renamed to ‘FileUploadCustomControl’. Also rename the constructor. The code in the constructor will be as below:
 
static FileUploadCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FileUploadCustomControl),
 
newFrameworkPropertyMetadata(typeof(FileUploadCustomControl)));
}
Define TextBox and Button at class level as shown below. This will be instantiated using the controls names set in the template XAML above in Step 3.
 
TextBox txtFileName = null;
Button btnBrowse = null;
 .
Since this control is used to upload the image and this will be displayed in the container of this control, I have declared the following dependency property name ‘FileName’.
 .
public string FileName
{
    get { return (string)GetValue(FileNameProperty); }
    set { SetValue(FileNameProperty, value); }
}
 
// Using a DependencyProperty as the backing store for FileName. This enables animation, styling, binding, etc…
public static readonly DependencyProperty FileNameProperty =
    DependencyProperty.Register(“FileName”, typeof(string),typeof(FileUploadCustomControl),
        new FrameworkPropertyMetadata(string.Empty,FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
 .
Since the control has to expose the ‘FileName’ property to its container application, the CC should declare the following routed event:
 
public event RoutedEventHandler FileNameChanged
{
    add { AddHandler(FileNameChangedEvent, value); }
    remove { RemoveHandler(FileNameChangedEvent, value); }
}
 
public static readonly RoutedEvent FileNameChangedEvent =
    EventManager.RegisterRoutedEvent(“FileNameChanged”,
    RoutingStrategy.Bubble, typeof(RoutedEventHandler),typeof(FileUploadCustomControl));
 
Now it’s time to construct the control, so override ‘OnApplyTemplate()’ method as below:
 
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
 
    txtFileName = this.Template.FindName(“TXT_FILE_NAME”, this) as TextBox;
 
    btnBrowse = this.Template.FindName(“BTN_BROWSE_FILE”, this) as Button;
    btnBrowse.Click += new RoutedEventHandler(btnBrowse_Click);
    txtFileName.TextChanged += new TextChangedEventHandler(txtFileName_TextChanged);
}
 .
The above method shows how the Button and TextBox objects are created using the respective control name from the ‘Generic.xaml’.
Write the following code in the Browse button event. This code will launch the open dialog box and then the file can be selected.
 
void btnBrowse_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog fileDIalog = new OpenFileDialog();
    fileDIalog.Filter = “Image files (*.bmp, *.jpg)|*.bmp;*.jpg|Doc Files (*.doc;*.docx)|*.doc;*.docx”;
    fileDIalog.AddExtension = true;
    if (fileDIalog.ShowDialog() == true)
    {
        FileName = fileDIalog.FileName;
        txtFileName.Text = FileName;
    }
}
 .
Write the following code in the TextChanged event of the textbox, here e.Handled = True’ will stop the event at the control level itself and the ‘FileNameChanged’ is raised. This event is then handled in the container WPF application.
 
void txtFileName_TextChanged(object sender, TextChangedEventArgs e)
{
    e.Handled = true;
 
    base.RaiseEvent(new RoutedEventArgs(FileNameChangedEvent));
}
 .
That’s it. Build the control.

Create a WPF Application for using the Custom Control.

Step 1: In the same solution, add a new WPF Application and name it as ‘WPF40_FileUploadContainer’.

Step 2: In this project, add the reference of the ‘WPF40_FileUploadCustomControl’ library so that the control can be used.
Step 3: Open MainWindow.Xaml and register the control in XAML (Gray Marked). Use the control in XAML and subscribe the ‘FileNameChanged’ event (Green Marked) as shown below :
<Window x:Class=”WPF40_FileUploadContainer.MainWindow”
        xmlns:ccFileUpload=”clr-namespace:WPF40_FileUploadCustomControl;assembly=WPF40_FileUploadCustomControl”
        Title=”MainWindow” Height=”481″ Width=”667″>
    <Grid>
        <Grid.RowDefinitions>
           <RowDefinition Height=”112*” />
            <RowDefinition Height=”330*” />
        </Grid.RowDefinitions>
        <ccFileUpload:FileUploadCustomControl x:Name=”fileUpload”
                                              Width=”600″ Margin=”12,29,34,0″Height=”56″
                                              VerticalAlignment=”Top”
                                              FileNameChanged=”fileUpload_FileNameChanged”></ccFileUpload:FileUploadCustomControl>
        <Image Grid.Row=”1″ Height=”264″ HorizontalAlignment=”Left” Margin=”30,24,0,0″Name=”imgUploaded” Stretch=”Fill” VerticalAlignment=”Top” Width=”589″ />
    </Grid>
</Window>
Step 4: Open MainWindow.Xaml.cs and write the following code in it:
 
private void fileUpload_FileNameChanged(object sender, RoutedEventArgs e)
{
    ImageSource imgSrc = new BitmapImage(new Uri(fileUpload.FileName));
    imgUploaded.Source = imgSrc;
}
 
The above code represents the event handled on the container for the Custom Control.
Step 5: Run the application.
Once the WPF window runs, click on ‘Browse’ button and the open dialog box will be displayed. Select a ‘.jpg’ file and click on ‘Open’ button. The selected image will be displayed as shown below:
WPF Custom Control
Conclusion:  
 .
WPF allows us to develop specialty controls using Custom Control. Before deciding to use a Custom Control, one must think about,
.

What functionality will be performed by the control?

This will help in selecting Visual Elements for designing UI for the control, along with the business logic for it.
.
What data will be either consumed by the control or published from the control?
This will help in defining dependency properties for the control. These properties will be used in DataBinding.
.
When will this control publish the data to its container?
This will help in defining routed event for the controls.
Advertisements
Categories: WPF Tags:
%d bloggers like this: