Создание своего свойства и привязка к нему данных

Создал новый проект, в нём определил свою кнопку с новым свойством "TextField_1":

public partial class MyButton : Button
    {
        public string TextField_1
        {
            get; set;
        }

        [Bindable(true, BindingDirection.TwoWay)]
        [Category("TextField_1")]
        public static readonly DependencyProperty TextField_1Property = DependencyProperty.RegisterAttached(
            "TextField_1",
            typeof(string),
            typeof(MyButton),
            new FrameworkPropertyMetadata("", new PropertyChangedCallback(OnTextField_1Changed))
            );

        public static void SetTextField_1(UIElement obj, string value)
        {
            obj.SetValue(TextField_1Property, value);
        }

        public static string GetTextField_1(UIElement obj)
        {
            return (string)obj.GetValue(TextField_1Property);
        }

        private static readonly DependencyPropertyKey TextField_1PropertyKey = DependencyProperty.RegisterReadOnly(
            "TextField_1PropertyKey", 
            typeof(bool), 
            typeof(MyButton), 
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None));

        private static void OnTextField_1Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MyButton MycontentControl = d as MyButton;
            MycontentControl.SetValue(TextField_1PropertyKey, e.NewValue != null);
            MycontentControl.OnContentChanged((string)e.OldValue, (string)e.NewValue);
        }
}

По сути, "TextField_1" добавляет второе свойство "Content". Потом создал кнопку в XAML:

<local:MyButton x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="80,65,0,0" VerticalAlignment="Top" Width="230" Height="300" Style="{DynamicResource MyButtonStyle1}"/>

и стиль для неё:

<Style x:Key="MyButtonStyle1" TargetType="{x:Type local:MyButton}">
            <Setter Property="Background" Value="#FFDDDDDD"/>
            <Setter Property="BorderBrush" Value="#FF707070"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MyButton}">
                        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                            <Grid x:Name="grid" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}">
                                <Label x:Name="label" Content="TextField_1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
                                <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="10,40.96,0,0" TextWrapping="Wrap" Text="{TemplateBinding TextField_1}" VerticalAlignment="Top" Width="120"/>
                                <Label x:Name="label_Copy1" Content="Content" HorizontalAlignment="Left" Margin="10,86.04,0,0" VerticalAlignment="Top"/>
                                <TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="10,117,0,0" TextWrapping="Wrap" Text="{TemplateBinding Content}" VerticalAlignment="Top" Width="120"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

В стиле поле "Text" у "textBox1" связал со своим новым свойством "{TemplateBinding TextField_1}".

В самом дизайнере, если зайти в свойства кнопки и вручную изменить поле "TextField_1", то установленное значение сразу же отображается в "textBox1". Но после запуска программы, если программно установить значение для "TextField_1", то само значение меняется, а вот "Text" у "textBox1" нет. Я так понимаю, я где-то не правильно создал привязку.

Помоги, пожалуйста, я уже всё перепробовал, даже метод "тыка" не помогает...

*П.С. Если использовать родное свойство "Content", то всё прекрасно.

П.П.С. Создание "UserControl" с "InitializeComponent" не помогает. "ContentPresenter" так же ни на что не влияет.*


Ответы (1 шт):

Автор решения: aepot

Ваше присоединенное свойство просто не поддерживает по умолчанию двухстороннюю привязку. Но это можно исправить.

Аттрибут

[Bindable(true, BindingDirection.TwoWay)]

Ни на что не влияет в поведении свойства, это всего-лишь метаданные для визуального редактора WPF.

Переключить поведение по умолчанию можно вот так:

public static readonly DependencyProperty TextField_1Property = DependencyProperty.RegisterAttached(
    "TextField_1",
    typeof(string),
    typeof(MyButton),
    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnTextField_1Changed))
);

Так же изучите другие флаги FrameworkPropertyMetadataOptions и на что они влияют (ссылка).

Второй нюанс - это то что TemplateBinding всегда OneWay (ссылка).

Нужно вместо

<TextBox Text="{TemplateBinding TextField_1}"/>

Использовать

<TextBox Text="{Binding TextField_1, RelativeSource={RelativeSource TemplatedParent}}"/>

В сумме с FrameworkPropertyMetadataOptions.BindsTwoWayByDefault это даст нужный вам эффект.

И последнее: свойство есть, а к зависимости не подключено.

public string TextField_1
{
    get; set;
}

Надо вот так

public string TextField_1
{ 
    get => (string)GetValue(TextField_1Property);
    set => SetValue(TextField_1Property, value);
}  

P. S. Style="{DynamicResource MyButtonStyle1}" - используйте StaticResource.

→ Ссылка