Jeong Yo Han
Jeong Yo Han

Reputation: 600

Which page should I declare Binding Option with Custom control in WPF

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.

for helping your understand I added my reop for my source, below.

click here to see entire source

Upvotes: 2

Views: 116

Answers (1)

Clemens
Clemens

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

Related Questions