Twój typ powinien zaimplementować INotifyPropertyChanged
, aby kolekcja mogła wykryć zmiany. Jak Sam mówi, przekazać string.Empty
jako argument.
Musisz również trzeba mieć źródło danych jako kolekcję, która dostarcza powiadomienia o zmianie. Odbywa się to za pośrednictwem interfejsu INotifyCollectionChanged
(lub interfejsu niezupełnie-WPF IBindingList
).
Oczywiście musisz uruchomić interfejs INotifyCollectionChanged
, gdy jeden z elementów użytkownika INotifyPropertyChanged
wywoła swoje zdarzenie. Na szczęście istnieje kilka typów w ramach, które zapewniają tę logikę dla Ciebie. Prawdopodobnie najbardziej odpowiedni jest ObservableCollection<T>
. Jeśli podłączysz swoje ListBox
do ObservableCollection<FooBar>
, to połączenie zdarzeń nastąpi automatycznie.
W pokrewnym notatniku nie trzeba używać metody ToString
tylko po to, aby uzyskać WPF do renderowania obiektu w pożądany sposób. Można użyć DataTemplate
takiego:
<ListBox x:Name="listBox1">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:FooBar}">
<TextBlock Text="{Binding Path=Property}"/>
</DataTemplate>
</ListBox.Resources>
</ListBox>
W ten sposób można sterować prezentacji obiektu, gdzie należy - w XAML.
EDYTOWANIE 1 Zauważyłem twój komentarz, że używasz kolekcji ListBox.Items
jako kolekcji. Nie spowoduje to wymaganego powiązania. Lepiej rób coś w stylu:
var collection = new ObservableCollection<FooBar>();
collection.Add(fooBar1);
_listBox.ItemsSource = collection;
Nie sprawdziłem tego kodu pod kątem dokładności kompilacji, ale otrzymujesz istotę.
EDIT 2 Używanie podanego powyżej (edytowałem go w celu dopasowania do twojego kodu) rozwiązuje problem.
Wydaje się dziwne, że wyzwalanie PropertyChanged
nie powoduje aktualizacji elementu listy, ale użycie metody ToString
nie jest sposobem, w jaki program WPF miał działać.
Przy użyciu tego DataTemplate, interfejs użytkownika poprawnie wiąże się z dokładną właściwością.
Zadałem tu pytanie na jakiś czas dotyczące wykonania string formatting in a WPF binding. Może się to okazać pomocne.
EDYTOWANIE 3 Jestem zaskoczony, dlaczego to wciąż nie działa dla Ciebie. Oto pełny kod źródłowy okna, którego używam.
Kod za:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace StackOverflow.ListBoxBindingExample
{
public partial class Window1
{
private readonly FooBar _fooBar;
public Window1()
{
InitializeComponent();
_fooBar = new FooBar("Original value");
listBox1.ItemsSource = new ObservableCollection<FooBar> { _fooBar };
}
private void button1_Click(object sender, RoutedEventArgs e)
{
_fooBar.Property = "Changed value";
}
}
public sealed class FooBar : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string m_Property;
public FooBar(string initval)
{
m_Property = initval;
}
public string Property
{
get { return m_Property; }
set
{
m_Property = value;
OnPropertyChanged("Property");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
XAML:
<Window x:Class="StackOverflow.ListBoxBindingExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow.ListBoxBindingExample"
Title="Window1" Height="300" Width="300">
<DockPanel LastChildFill="True">
<Button Click="button1_Click" DockPanel.Dock="Top">Click Me!</Button>
<ListBox x:Name="listBox1">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:FooBar}">
<TextBlock Text="{Binding Path=Property}"/>
</DataTemplate>
</ListBox.Resources>
</ListBox>
</DockPanel>
</Window>
Zaktualizowałem swoją odpowiedź, aby pokazać, jak to działa. Wydaje się, że DataTemplate jest drogą do zrobienia. –