Pytanie Ustawianie niestandardowych właściwości w UserControl przez DataBinding


Załóżmy, że mam bardzo prostą UserControl, która - dla wszystkich intencji i celów - jest niczym więcej niż TextBox:

public partial class FooBox : UserControl
{
    public static readonly DependencyProperty FooTextProperty =
        DependencyProperty.Register("FooText", typeof(string), typeof(FooBox));

    public FooBox()
    {
        InitializeComponent();
    }

    public string FooText
    {
        get { return textBlock.Text; }
        set { textBlock.Text = value; }
    }
}

<UserControl x:Class="Namespace.FooBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
        <TextBlock x:Name="textBlock" />
    </Grid>
</UserControl>

W formularzu jest zadeklarowany jako:

<local:FooBox FooText="{Binding Name}" />

DataContext formularza jest ustawiony na obiekt, który ma właściwość Name. Ale to nie działa dla mnie. czego mi brakuje?


14
2018-05-10 15:58


pochodzenie




Odpowiedzi:


Części "get" i "set" deklaracji właściwości w zależności DependencyProperty nie są w rzeczywistości wywoływane przez system szyfrowania danych w WPF - są tam zasadniczo tylko po to, aby spełnić wymagania kompilatora.

Zamiast tego zmień deklarację właściwości, aby wyglądała następująco:

public string FooText
{
    get { return (string)GetValue(FooTextProperty); }
    set { SetValue(FooTextProperty, value); }
}

... i twój XAML do:

<UserControl ...
    x:Name="me">
    <Grid>
        <TextBlock Text="{Binding FooText,ElementName=me}" />
    </Grid>
</UserControl>

Teraz twój TextBox.Text po prostu wiąże się bezpośrednio z właściwością "FooText", więc możesz z kolei powiązać właściwość FooText z "Name" tak jak obecnie.

Innym sposobem jest powiązanie TextBlock.Text z wiązaniem RelativeSource, które znajduje właściwość FooText na pierwszym przodku typu "FooBox", ale odkryłem, że jest to bardziej skomplikowane niż podawanie kontrolce wewnętrznego elementu x: Name i using wiążący.


19
2018-05-10 22:57



Będę głosować, ponieważ pomogłeś mi zbliżyć się do tego, czego mi brakowało. Ale tutaj mój testowy przypadek był zbyt prosty, by pokazać prawdziwy problem. Zobacz moją odpowiedź. - xanadont


Okazuje się, że prawdziwym problemem jest to, że oczekiwałem, że struktura WPF ustawi moją własność publiczną, po czym mój kod zareaguje na zmiany i wyrenderuje zgodnie z nową wartością. Bynajmniej. Co robi WPF to wywołanie SetValue () bezpośrednio i całkowicie omija właściwość publiczną. Co musiałem zrobić, to otrzymywać powiadomienia o zmianie właściwości za pomocą DependencyPropertyDescriptor.AddValueChanged i odpowiadać na to. Wygląda to jak (wewnątrz ctor):

var dpd = DependencyPropertyDescriptor
    .FromProperty(MyDependencyProperty, typeof(MyClass));
dpd.AddValueChanged(this, (sender, args) =>
{
    // Do my updating.
});

5
2018-05-11 03:00



Należy również zauważyć, że metoda Register dla właściwości zależności ma przeciążenia, które mogą akceptować procedury obsługi zdarzeń uruchamiane za każdym razem, gdy właściwość się zmienia lub uległa zmianie. To może być miejsce na umieszczenie tam logiki. - Matt Hamilton