Reputation: 954
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
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
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
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