Frage

Warum ist es so, dass wenn ich mit einem Konverter in mein verbindliches Ausdruck in WPF, wird der Wert nicht aktualisiert, wenn die Daten aktualisiert werden.

Ich habe eine einfache Person Daten Modell:

class Person : INotifyPropertyChanged
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Meine Bindung zum Ausdruck sieht wie folgt aus:

<TextBlock Text="{Binding Converter={StaticResource personNameConverter}" />

Mein Konverter sieht wie folgt aus:

class PersonNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Person p = value as Person;
        return p.FirstName + " " + p.LastName;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Wenn ich die Daten gebunden werden, ohne einen Konverter, es funktioniert Super:

<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />

Was vermisse ich?

EDIT:Nur um zu klären ein paar Dinge, beide, Joel und Alan sind richtig in Bezug auf die INotifyPropertyChanged-interface, die muss umgesetzt werden.In Wirklichkeit habe ich tatsächlich implementieren, aber es funktioniert immer noch nicht.

Ich kann nicht mehrere TextBlock-Elemente, weil ich versuche, mich zu binden, Fenster-Titel, um den vollständigen Namen und den Titel des Fensters nicht nehmen eine Vorlage aus.

Schließlich ist es eine option für das hinzufügen eine compound-Eigenschaft "FullName" und zu binden, aber ich bin immer noch Fragen, warum die Aktualisierung geschieht nicht, wenn die Bindung verwendet ein Konverter.Sogar, wenn ich einen Haltepunkt in den code converter, debugger einfach nicht bekommen es, wenn ein update durchgeführt, um die zugrunde liegenden Daten :-(

Vielen Dank, Uri

War es hilfreich?

Lösung

(siehe änderungen unten;neueste:#2)

Es ist nicht aktualisieren, weil Ihre Person Objekt ist nicht in der Lage, Benachrichtigen alles, was der Wert von FirstName oder LastName hat sich geändert. Siehe diese Frage.

Und hier ist, wie Sie umzusetzen INotifyPropertyChanged. (Aktualisiert, finden Sie unter Bearbeiten 2)

using System.ComponentModel;

class Person : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    string _firstname;
    public string FirstName {
        get {
            return _firstname;
        }
        set {
            _firstname = value;
            onPropertyChanged( "FirstName", "FullName" );
        }
    }

    string _lastname;
    public string LastName {
        get {
            return _lastname;
        }
        set {
            _lastname = value;
            onPropertyChanged( "LastName", "FullName" );
        }
    }

    public string FullName {
        get {
            return _firstname + " " + _lastname;
        }
    }

    void onPropertyChanged( params string[] propertyNames ) {
        PropertyChangedEventHandler handler = PropertyChanged;

        if ( handler != null ) {
            foreach ( var pn in propertyNames ) {
                handler( this, new PropertyChangedEventArgs( pn ) );
            }
        }
    }
}

Bearbeiten 1

Tatsächlich, da Sie nach dem Vornamen und Nachnamen aktualisieren, und Path=FirstName und so funktioniert Prima, ich glaube nicht, benötigen Sie den Konverter an alle.Mehrere TextBlocks nur als gültig, und kann tatsächlich besser funktionieren, wenn Sie die Lokalisierung zu einer rechts-nach-Links-Sprache.

Bearbeiten 2

Ich habe es herausgefunden.Es ist nicht darüber informiert, dass die Eigenschaften aktualisiert, da es die Bindung an das Objekt selbst, nicht eine von diesen Eigenschaften.Auch wenn ich aus Person ein DependencyObject und aus FirstName und LastName DependencyProperties, wäre es nicht aktualisieren.

Sie wird die Verwendung einer FullName Eigentum, und ich habe den code aktualisieren, der Person Klasse oben zu reflektieren.Dann können Sie die binden Title. (Hinweis: Ich habe den Person Objekt als Window's DataContext.)

Title="{Binding Path=FullName, Mode=OneWay}"

Wenn Sie das Bearbeiten der Namen in einer TextBox und der name änderte sich sofort statt, wenn die TextBox den Fokus verliert, können Sie dies tun:

<TextBox Name="FirstNameEdit"
    Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />

Ich kenne Sie nicht wollen, zu verwenden eine FullName Eigenschaft, sondern etwas, dass würde erreichen, was Sie wollen, wäre wahrscheinlich ein bisschen von einer Rube-Goldberg-Gerät.Wie der Umsetzung INotifyPropertyChanged und eine Person Eigenschaft der Window Klasse selbst, mit der Window hören Sie auf die PropertyChanged Ereignis, um das Feuer Window's PropertyChanged Ereignis, und verwenden eine relative Bindung wie die folgenden.Hättest du auch haben die Person Eigenschaft vor InitializeComponent() oder Feuer PropertyChanged nach der Einstellung der Person Immobilie, so dass es sich zeigt, natürlich.(Sonst wird es werden null während InitializeComponent() und muss wissen wenn es ein Person.)

<Window.Resources>
    <loc:PersonNameConverter
        x:Key="conv" />
</Window.Resources>
<Window.Title>
    <Binding
        RelativeSource="{RelativeSource Self}"
        Converter="{StaticResource conv}"
        Path="Person"
        Mode="OneWay" />
</Window.Title>

Andere Tipps

Sie können auch eine Multibinding .. binden an das Objekt Person, die Vor- und den Nachnamen verwenden. Auf diese Weise wird der Wert, sobald Vorname oder Nachname wirft die Eigenschaft geänderte Ereignis aktualisiert.

<MultiBinding Converter="{IMultiValueConverter goes here..}">
    <Binding />
    <Binding Path="FirstName" />
    <Binding Path="LastName" />
</MultiBinding>

Oder wenn Sie nur das Vorname verwenden und Nachname, Streifen der Person-Objekt aus der Bindung an etwas wie folgt aus:

<MultiBinding Converter="{IMultiValueConverter goes here..}">
    <Binding Path="FirstName" />
    <Binding Path="LastName" />
</MultiBinding>

Und die MultiValueConverter sieht wie folgt aus:

class PersonNameConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
            return values[0].ToString() + " " + values[1].ToString();
    }

    public object ConvertBack(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
            throw new NotImplementedException();
    }
}

Aber natürlich die gewählte Antwort funktioniert auch, aber ein Multibinding arbeitet elegante ...

Damit die Bindung aktualisiert werden, muss Ihre Person Klasse INotifyPropertyChanged implementieren die Bindung zu können, dass die Eigenschaften des Objekts haben udpated worden. Sie können auch Sie sich von den zusätzlichen Konverter sparen, indem ein Fullname-Eigenschaft bereitstellt.

using System.ComponentModel;

namespace INotifyPropertyChangeSample
{
    public class Person : INotifyPropertyChanged
    {
        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    OnPropertyChanged("FirstName");
                    OnPropertyChanged("FullName");
                }
            }
        }

        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    OnPropertyChanged("LastName");
                    OnPropertyChanged("FullName");
                }
            }
        }

        public string FullName
        {
            get { return firstName + " " + lastName; }
        } 

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}

Ihre Bindung wird nun wie folgt aussehen:

<TextBlock Text="{Binding Person.FullName}" />

Ich habe überprüfen Sie es nicht, aber Sie können auch versuchen, die folgende

<TextBlock Text="{Binding Path=/, Converter={StaticResource personNameConverter}}" />
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top