Erik
Erik

Reputation: 954

How can prevent reapeating this piece of code 10 times?

I use 10 of the grids like below in my XAML, each time with other binding sources. Do I have to repeat (copy/paste) this code 10 times or is there a better way? (template?)

<Grid>                               
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition />
     </Grid.RowDefinitions>
     <TextBox
           Style="{StaticResource TBGrid}"
           Grid.Column="0"
           Grid.Row="0"
           Text="{Binding ...}" />
     <Label
          Style="{StaticResource TBLabel}"
          Grid.Column="1"
          Grid.Row="0"
          Content="{Binding....}" />
</Grid>

Now I have this code, with help from commenters, and it seems to work:

using System.Windows;
using System.Windows.Controls;

namespace MVVMCable
{
    /// <summary>
    /// Interaction logic for ArrowLabel.xaml
    /// </summary>
    public partial class ArrowLabel : UserControl
    {
        public ArrowLabel()
        {
            InitializeComponent();
            this.DataContext = this;  //  <==== this must be added, seemingly.
        }
        public static readonly DependencyProperty TextBoxTextProperty = DependencyProperty.Register
            (
                "TextBoxText",
                typeof(string),
                typeof(ArrowLabel),
                new PropertyMetadata("")
            );

        public string TextBoxText
        {
            get { return this.GetValue(TextBoxTextProperty) as string; }
            set { this.SetValue(TextBoxTextProperty, value); }
        }

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

        public string LabelText
        {
            get { return this.GetValue(LabelTextProperty) as string; }
            set { this.SetValue(LabelTextProperty, value); }
        }
    }
}

XAML:

<UserControl
    x:Class="MVVMCable.ArrowLabel"
    x:Name="MyArrowLabel"
    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"
    mc:Ignorable="d"
    d:DesignHeight="137.8"
    d:DesignWidth="279.2">
    <Grid
        Width="70"
        Height="15">
        <Grid.ColumnDefinitions>
            <ColumnDefinition
                Width="40"/>
            <ColumnDefinition
                Width="30"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition
                Height="14" />
        </Grid.RowDefinitions>
        <TextBox
            Height="20"
            Grid.Column="0"
            Grid.Row="0"
            IsEnabled="False"
            HorizontalContentAlignment="Right"
            Width="30"
            Text="{Binding ElementName=MyArrowLabel, Path=TextBoxText}"/>
        <Label
            Height="auto"
            Grid.Column="1"
            Grid.Row="0"
            HorizontalContentAlignment="Left"
            Width="auto"
            Content="{Binding ElementName=MyArrowLabel, Path=LabelText}"/>

    </Grid>
</UserControl>

And I use it in my app like this:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:MVVMCable"
    xmlns:oxy="http://oxyplot.org/wpf"
    xmlns:shapes="clr-namespace:MVVMCable.Views"
    xmlns:core="clr-namespace:System;assembly=mscorlib"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="MVVMCable.MainWindow"
    .......
     <c:ArrowLabel
         Canvas.Left="10"
         Canvas.Top="6"
         TextBoxText="{Binding Cable.RHVc}"  <== error here and
         LabelText="{Binding Units[X].Display}" />   <== here

Error text is:

Error 2 The member "LabelText" is not recognized or is not accessible.

And after adding this.DataContext = this;, things seem to work.

Upvotes: 0

Views: 107

Answers (3)

d.moncada
d.moncada

Reputation: 17402

Because there is going to be different DataContext for each, I would recommend a custom UserControl.

For example:

The UserControl itself will have the repeated XAML

<UserControl
    x:Class="SpecialUserControl"
    x:Name="MyUserControl"
    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"
    mc:Ignorable="d">
    <Grid>                               
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
         </Grid.RowDefinitions>
         <TextBox
               Style="{StaticResource TBGrid}"
               Grid.Column="0"
               Grid.Row="0"
               Text="{Binding ElementName=MyUserControl, Path=TextBoxText}" />
         <Label
              Style="{StaticResource TBLabel}"
              Grid.Column="1"
              Grid.Row="0"
              Content="{Binding ElementName=MyUserControl, Path=LabelText}" />
    </Grid>
</UserControl>

Code Behind of the UserControl will have two DependencyProperties

public static readonly DependencyProperty TextBoxTextProperty = 
    DependencyProperty.Register
    (
        "TextBoxText", 
        typeof(string), 
        typeof(SpecialUserControl),
        new PropertyMetadata("")
    );

public string TextBoxText
{
    get { return this.GetValue(TextBoxTextProperty) as string; }
    set { this.SetValue(TextBoxTextProperty, value); }
}

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

public string LabelText
{
    get { return this.GetValue(LabelTextProperty) as string; }
    set { this.SetValue(LabelTextProperty, value); }
}

If you notice, the UserControl XAML actually bind to these DependencyProperties for the TextBox and Label controls.

Now for usage, all you will have to do is use the defined DependencyProperties to bind to whatever you will like:

<namespace:SpecialUserControl 
    TextBoxText="{Binding ThisIsABinding}" 
    LabelText="{Binding ThisIsAnotherBinding}"/>

Upvotes: 4

Gul Ershad
Gul Ershad

Reputation: 1771

You can create custom field control by dependency property. In this field control you can combine label and text box feature together. Then you can put control in the stackpanel. So, It will remove the redundant code.

Upvotes: 0

VidasV
VidasV

Reputation: 4895

If the bindings could be standartized to most cases and you could switch only the context, then you should create a UserControl, put your content in there. And use it wherever you need instead of repeating code, just changing the DataContext they are bound to.

Upvotes: 0

Related Questions