Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a custom UI element in WPF

Tags:

c#

wpf

xaml

I have a several TextBoxes with Labels in my code which are implemented with the following XAML:

<DockPanel HorizontalAlignment="Right">
    <TextBlock Foreground="Black" Padding="0,0,10,0">Serial Number:</TextBlock>
    <TextBox Width="150" IsReadOnly="True" BorderBrush="Gainsboro" Height="20"></TextBox>
</DockPanel>

I can reduce some of the copied code by doing something like:

<DockPanel HorizontalAlignment="Right">
    <TextBlock Style="{StaticResource CstmTextBoxLbl}">Serial Number:</TextBlock>
    <TextBox Style="{StaticResource CstmTextBox}"></TextBox>
</DockPanel>

but it is still somewhat lengthy. Is it possible to do something like:

<controls:CstmTextBox Style="{StaticResource CstmTextBox}" LabelText="Serial Number:" Text=""/>

Where the CstmTextBox would implement the whatever XAML is needed to get the same visual effect once, and I could access both the TextBlock text and the TextBox text in the code. Such as

CstmTextBox textbox;
textbox.LabelText = "Serial Number:";
String some_text = textbox.Text;

textbox.Text = "....";
like image 769
JME Avatar asked Jul 22 '15 16:07

JME


People also ask

How do I customize WPF controls?

Create a new WPF project and then right-click on your solution and select Add > New Item... It will open the following window. Now select Custom Control (WPF) and name it MyCustomControl. Click the Add button and you will see that two new files (Themes/Generic.

What is UIElement WPF?

UIElement is a base class for WPF core level implementations building on Windows Presentation Foundation (WPF) elements and basic presentation characteristics.

How many UI containers are available with WPF?

User Interface Panels. There are six panel classes available in UI scenarios: Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanel, and WrapPanel.

What is user control in WPF?

User controls, in WPF represented by the UserControl class, is the concept of grouping markup and code into a reusable container, so that the same interface, with the same functionality, can be used in several different places and even across several applications.


2 Answers

A UserControl or a CustomControl serves your needs. This is the code for a CustomControl.

C#:

public class CstmTextBox : Control
{
    public string LabelText
    {
        get
        {
            return (string)GetValue (LabelTextProperty);
        }
        set
        {
            SetValue (LabelTextProperty, value);
        }
    }

    public static readonly DependencyProperty LabelTextProperty =
        DependencyProperty.Register ("LabelText", typeof (string), typeof (CstmTextBox), new PropertyMetadata (string.Empty));

    public string Text
    {
        get
        {
            return (string)GetValue (TextProperty);
        }
        set
        {
            SetValue (TextProperty, value);
        }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register ("Text", typeof (string), typeof (CstmTextBox), new PropertyMetadata (string.Empty));
}

XAML:

    <Style TargetType="{x:Type controls:CstmTextBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:CstmTextBox}">
                    <DockPanel HorizontalAlignment="Right">
                        <TextBlock Foreground="Black" Padding="0,0,10,0" Text="{TemplateBinding LabelText}"/>
                        <TextBox Width="150" IsReadOnly="True" BorderBrush="Gainsboro" Height="20" Text="{TemplateBinding Text}"/>
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Add the style to your resources and use the new control:

    <controls:CstmTextBox LabelText="abcde" Text="1234"/>
like image 180
gomi42 Avatar answered Oct 23 '22 15:10

gomi42


Add a UserControl to your solution, and copy the XAML you want to reuse inside.

If you set x:Name to the controls inside your UserControl...

<UserControl ... >
    <DockPanel HorizontalAlignment="Right">
        <TextBlock x:Name="SerialNumberTextBlock" Style="{StaticResource CstmTextBoxLbl}">Serial Number:</TextBlock>
        <TextBox x:Name="SerialNumberTextBox" Style="{StaticResource CstmTextBox}"></TextBox>
    </DockPanel>
</UserControl>

... you'll be able to access them from outside (code-behind) like this:

CstmTextBox textbox;
textbox.SerialNumberTextBlock.Text = "Serial Number:";
String some_text = textbox.SerialNumberTextBox.Text;

textbox.SerialNumberTextBox.Text = "....";

But it's even better if you create DependencyProperties for the properties you want to expose. You define those properties in the code-behind of your UserControl:

public string Text
{
    get
    {
        return (string)GetValue(TextProperty);
    }
    set
    {
        SetValue (TextProperty, value);
    }
}

public static readonly DependencyProperty TextProperty = 
    DependencyProperty.Register("Text", typeof(string), typeof (CstmTextBox));

Then bind those properties to the controls inside your UserControl:

<UserControl x:Name="Root" ... >
    <DockPanel HorizontalAlignment="Right">
        <TextBlock x:Name="SerialNumberTextBlock" Style="{StaticResource CstmTextBoxLbl}"
                   Text="{Binding LabelText, ElementName=Root}" />
        <TextBox x:Name="SerialNumberTextBox" Style="{StaticResource CstmTextBox}"
                 Text="{Binding Text, ElementName=Root, Mode=TwoWay}" />
    </DockPanel>
</UserControl>

That way you can set the properties directly from outside, be it code-behind, XAML or Binding.

like image 24
almulo Avatar answered Oct 23 '22 13:10

almulo