Search code examples
wpfuser-controlsstyling

WPF reusable label and text box row


In my application I have a form which contains a lot of rows
with the repeated pattern of :
Label and than a Textbox next to it.

   <Grid.ColumnDefinitions>
  
   </Grid.ColumnDefinitions>

I am new to wpf but is there a way to create something like a user control which contains these two controls together ?
And each time I just add this new control and modify the Label's content.


Solution

  • Of course there is a way and it is called UserControl. Just right click your project and select Add New Item. Then browse to add a UserControl, here is an example:

    <UserControl x:Class="WpfApp.MyUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:local="clr-namespace:WpfApp"
                 mc:Ignorable="d"
                 d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="4*" />
                <ColumnDefinition Width="6*" />
            </Grid.ColumnDefinitions>
    
            <Label x:Name="lbl"  />
            <TextBox Grid.Column="1" Height="20" Width="100" />
        </Grid>
    </UserControl>
    

    Then for managing the content of the lable you will need a dependency property so that whatever is consuming your user control can bind to it (you can use regular properties too but then binding will not be possible):

    public partial class MyUserControl : UserControl
    {
        public static readonly DependencyProperty LabelContentProperty = DependencyProperty.Register(
            "LabelContent", typeof(string), typeof(MyUserControl), new PropertyMetadata(default(string),OnLabelContentChanged));
    
        private static void OnLabelContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (MyUserControl) d;
            control.lbl.Content = e.NewValue;
        }
    
        public string LabelContent
        {
            get => (string) GetValue(LabelContentProperty);
            set => SetValue(LabelContentProperty, value);
        }
    
        public MyUserControl()
        {
            InitializeComponent();
        }
    }
    

    In case you do not want to use dependency properties then you will be fine with something similar to:

    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    
        public string LabelContent
        {
            get => lbl.Content as string;
            set => lbl.Content = value;
        }
    }
    

    And then just use it!

    <Window x:Class="WpfApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:wpfApp="clr-namespace:WpfApp"
            mc:Ignorable="d"
            WindowStartupLocation="Manual"
            Title="MainWindow">
        <Grid>
            <wpfApp:MyUserControl LabelContent="Hi there!"/>
        </Grid>
    </Window>