Reputation: 206
I have DependencyProperty
in my custom control. I bound it to some property in some object. When my control appears, it takes value from source and applies it to itself. But when I type something in the input field, source value doesn't change. What am I doing wrong?
Control declaration:
public class ScriptComponentField : Control
{
public enum Datatype
{
String,
Integer,
Real,
Boolean,
Enumerable,
Code
}
public string Header
{
get { return (String)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached(nameof(Header), typeof(string), typeof(ScriptComponentField), new PropertyMetadata(""));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(nameof(Value), typeof(object), typeof(ScriptComponentField), new PropertyMetadata(null));
public Datatype ValueType
{
get { return (Datatype)GetValue(ValueTypeProperty); }
set { SetValue(ValueTypeProperty, Value); }
}
public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.RegisterAttached(nameof(ValueType), typeof(Datatype), typeof(ScriptComponentField), new PropertyMetadata(Datatype.String));
public List<string> EnumerableItems
{
get { return (List<string>)GetValue(EnumerableItemsProperty); }
set { SetValue(EnumerableItemsProperty, Value); }
}
public static readonly DependencyProperty EnumerableItemsProperty = DependencyProperty.RegisterAttached(nameof(EnumerableItems), typeof(List<string>), typeof(ScriptComponentField), new PropertyMetadata(null));
static ScriptComponentField()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptComponentField), new FrameworkPropertyMetadata(typeof(ScriptComponentField)));
}
}
Property Value
has object
type just because it can contain any value like string
, bool
, int
and etc.
Control template:
<Style TargetType="{x:Type Controls:ScriptComponentField}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Controls:ScriptComponentField}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" SharedSizeGroup="name"/>
<ColumnDefinition SharedSizeGroup="value"/>
</Grid.ColumnDefinitions>
<Label Content="{TemplateBinding Header}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox x:Name="InputString" Visibility="Collapsed" Grid.Column="1" Text="{TemplateBinding Value}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>
<Advanced:IntegerUpDown x:Name="InputInteger" Visibility="Collapsed" Grid.Column="1" Value="{TemplateBinding Value}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>
<CheckBox x:Name="InputBoolean" Visibility="Collapsed" Grid.Column="1" IsChecked="{TemplateBinding Value}" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ValueType" Value="String">
<Setter TargetName="InputString" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="ValueType" Value="Integer">
<Setter TargetName="InputInteger" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="ValueType" Value="Boolean">
<Setter TargetName="InputBoolean" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Upvotes: 1
Views: 80
Reputation: 438
You might have missed the "Mode=TwoWay" property, as follows:
<Button x:Name="btnMy" Content="{Binding MyText, Mode=TwoWay}" />
Default control binding is "OneWay" (See EDIT below), which "Updates the binding target (target) property when the binding source (source) changes." © MSDN link below
TwoWay Binding: "Causes changes to either the source property or the target property to automatically update the other" © MSDN link below
EDIT:
As noted by Clemens, regarding the default binding mode:
"The default mode is set during registration of a property, by FrameworkPropertyMetadataOptions." © Clemens
Is short, it isn't always OneWay, but most of the times.
Upvotes: 0
Reputation: 7325
The problem is that you use TemplateBinding
. TemplateBinding
is always OneWay
. If you change your TemplateBinding
to the TwoWay
Binding
with RelativeSource
or with ElementName
it will work.
<TextBox x:Name="InputString" Visibility="Collapsed" Grid.Column="1" Text="{Binding Value, RelativeSource={RelativeSource AncestorType=Controls:ScriptComponentField}, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>
Upvotes: 1