Reputation: 600
I'm new to make custom control in wpf.
I quite don't understand binding technique with custom control.
Let me show you my exercise.
I declare my custom control in cs file
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata
(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))
);
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextaaProperty =
DependencyProperty.Register(
"Textaa",
typeof(string), typeof(CustomControl1),
new PropertyMetadata(null));
public string Textaa
{
get { return (string)GetValue(TextaaProperty); }
set { SetValue(TextaaProperty, value); }
}
}
and in Generic.xaml, I declared Template Style for my custom control in Generic.xaml.
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Background" Value="DimGray"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To Text my control, I made My Custom class for Data object that just have name property and just be inherited from INPC
public MainWindow()
{
InitializeComponent();
DataContext = new DataObject() { name = "Jeong Yo Han" };
}
public class DataObject : INotifyPropertyChanged
{
private string _name;
public string name
{
get { return _name; }
set {
_name = value;
onPropertyChanged("name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void onPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
In my MainWindow Page, I declared my custom control Tag
<Grid>
<cc:CustomControl1 Background="Red"
Textaa="{Binding name ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
</cc:CustomControl1>
</Grid>
I tried to test that does templatedParent in Template Style works for two-way binding. ( see a RelativeSource= { Rela ... TemplatedParent } ).
and I run my program to see when I get hit name setter property in DataObject class. even I add UpdateSourceTrigger=PropertyChanged, but It doesn't work well when I change text in my TextBox. It works when I lost focus on it, Even I typed UpdateSourceTrigger=PropertyChanged.
So I Changed my source Like following source.
<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red"
Textaa="{Binding name ,Mode=TwoWay}" >
</cc:CustomControl1>
this works well, as I expected.
and following is not working, Not I expected.
<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red"
Textaa="{Binding name}" >
</cc:CustomControl1>
But I'm Confusing that why I should put UpdateSourceTrigger Option to StyleTemplate and Mode= TwoWayBinding Option to directly Textaa dependency property of customcontrol tag.
I need an explanation. Thank you for reading.
click here to see entire source
Upvotes: 2
Views: 116
Reputation: 128013
The default behavior for updating the source property of a Binding of the Text property of a TextBox is LostFocus
.
See the Remarks on the TextBox.Text Property page:
When used in data-binding scenarios, this property uses the default update behavior of UpdateSourceTrigger.LostFocus.
You do however not need to set Mode=TwoWay
, because that is already the default. So the TextBox declaration should look like this:
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}" />
It is not necessary to set UpdateSourceTrigger=PropertyChanged
on the Binding of your Textaa
property, because (in contrast to TextBlock.Text
), the default behaviour of your custom dependency property is already PropertyChanged
.
You may also register your property in a way that makes it bind two-way by default, so that you would not have to set Mode=TwoWay
on the Textaa
Binding:
public static readonly DependencyProperty TextaaProperty =
DependencyProperty.Register(
nameof(Textaa), typeof(string), typeof(CustomControl1),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Now you can bind the Textaa
property like this:
<cc:CustomControl1 Textaa="{Binding name}" />
Upvotes: 3