Dot-Net

項目更改時更新 WPF 列表

  • August 25, 2011

我有一個 WPF 列錶框,並且添加了一些“FooBar”對像作為項目(通過程式碼)。FooBars 不是 WPF 對象,只是具有覆蓋 ToString() 函式的啞類。

現在,當我更改影響 ToString 的屬性時,我希望更新 ListBox。

  1. 我怎樣才能做到這一點“又快又髒”(比如重新粉刷)。
  2. 依賴屬性是解決這個問題的方法嗎?
  3. 是否值得/總是建議為我的 FooBars 創建一個 wpf 包裝類?

謝謝…

您的類型應該實現INotifyPropertyChanged,以便集合可以檢測到更改。正如 Sam 所說,string.Empty作為論點傳遞。

還需要讓ListBox的數據源成為提供更改通知的集合。這是通過INotifyCollectionChanged介面(或非 WPFIBindingList介面)完成的。

當然,您需要在INotifyCollectionChanged成員INotifyPropertyChanged項之一觸發其事件時觸發該介面。值得慶幸的是,框架中有一些類型可以為您提供這種邏輯。可能最合適的一個是ObservableCollection<T>。如果您將您的綁定ListBox到一個,ObservableCollection<FooBar>那麼事件連結將自動發生。

在相關說明中,您不必使用ToString方法來讓 WPF 以您想要的方式呈現對象。你可以使用DataTemplate這樣的:

<ListBox x:Name="listBox1">
   <ListBox.Resources>
       <DataTemplate DataType="{x:Type local:FooBar}">
           <TextBlock Text="{Binding Path=Property}"/>
       </DataTemplate>
   </ListBox.Resources>
</ListBox>

通過這種方式,您可以控制對象所屬的對象的呈現方式——在 XAML 中。

編輯 1我注意到您的評論是您正在使用該ListBox.Items集合作為您的集合。這不會進行所需的綁定。你最好做這樣的事情:

var collection = new ObservableCollection<FooBar>();
collection.Add(fooBar1);

_listBox.ItemsSource = collection;

我沒有檢查該程式碼的編譯準確性,但你明白了要點。

編輯 2使用DataTemplate我上面給出的(我編輯它以適應你的程式碼)解決了這個問題。

PropertyChanged觸發不會導致列表項更新似乎很奇怪,但是使用該ToString方法並不是 WPF 的預期工作方式。

使用此 DataTemplate,UI 可以正確綁定到確切的屬性。

不久前我在這裡問了一個關於在WPF 綁定中進行字元串格式化的問題。您可能會發現它很有幫助。

編輯 3我很困惑為什麼這仍然不適合你。這是我正在使用的視窗的完整原始碼。

後面的程式碼:

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>

引用自:https://stackoverflow.com/questions/553150