ARTICLE AD BOX
WPF is quite dated so I doubt they're are better snippets to speed up handling properties of custom controls aside from: propdp or propa. Of course, I'm open to getting corrected on this.
I think your approach to the problem can be improved. There's no need to create a new control each time you want to change behavior. Use ContentControl, AttachedProperties or Microsoft.Xaml.Behaviors where you can.
In this case, you can create a custom control and nest whatever you want in.
public class LabelHost : ContentControl { public string Label { get { return (string)GetValue(LabelProperty); } set { SetValue(LabelProperty, value); } } public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelHost), new PropertyMetadata("")); public HorizontalAlignment Alignment { get { return (HorizontalAlignment)GetValue(AlignmentProperty); } set { SetValue(AlignmentProperty, value); } } public static readonly DependencyProperty AlignmentProperty = DependencyProperty.Register("Alignment", typeof(HorizontalAlignment), typeof(LabelHost), new PropertyMetadata(HorizontalAlignment.Center)); }Your style declaration could look like this:
<!--#region LabelHost--> <ControlTemplate x:Key="LabelHostTemplate" TargetType="{x:Type ui:LabelHost}"> <Grid Background="Transparent"> <DockPanel> <ContentPresenter x:Name="PART_Presenter" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{TemplateBinding ContentControl.Content}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" DockPanel.Dock="Bottom" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> <Label HorizontalAlignment="{TemplateBinding Alignment}" Content="{TemplateBinding Label}" /> </DockPanel> </Grid> </ControlTemplate> <Style TargetType="{x:Type ui:LabelHost}"> <Setter Property="Template" Value="{StaticResource LabelHostTemplate}" /> </Style> <!--#endregion-->You could then use it like this:
<StackPanel> <ui:LabelHost Alignment="Right"> <TextBox /> </ui:LabelHost> <ui:LabelHost Alignment="Left"> <Button /> </ui:LabelHost> </StackPanel>If you'd still rather have your controls specifically defined, you could do something like this:
public class LabelTextBox : LabelHost { public LabelTextBox() { Content = new TextBox(); } } public class LabelTextBox2 : Border { private LabelHost _host; private TextBox _box; public LabelTextBox2() { _host = new LabelHost(); _box = new TextBox(); _host.Content = _box; _box.TextChanged += (s, e) => { // Custom code here... }; } }To deal with more complex logic, just check the Content property and adapt accordingly.
public class LabelHost : ContentControl { // ... public string TextContent { get { return (string)GetValue(TextContentProperty); } set { SetValue(TextContentProperty, value); } } public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(LabelHost), new PropertyMetadata("", HandleText)); private static void HandleText(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not LabelHost host) return; if (host.Content is TextBox textBox) { if (e.NewValue is string txt) textBox.Text = txt; // You can also just use Binding instead... } } }Of course you're free to create partial declarations of the class if you really really need it to be a large control without code clutter.
LabelHost.cs LabelHost.TextBox.cs LabelHost.Button.cs ...etc