2010-09-08 52 views
3

我有兩個集合顯示在我的WPF應用程序中,並且我想讓其中一個元素禁用。這樣做我創建了繼承ListBox的自定義控件FilteringListBox,並且我想在其中添加一些處理以禁用通過FilteringListBox上的屬性在集合集中設置的元素。現在,我的問題是,取決於我想過濾元素的ObservableCollection的依賴項屬性沒有設置 - 即使我將它綁定到xaml中。爲什麼我的依賴屬性在綁定時不能設置?

我創建了一個簡化的應用程序,在該應用程序中重現該問題。這是我的XAML:

<StackPanel> 
    <StackPanel Orientation="Horizontal"> 
     <StackPanel Orientation="Vertical"> 
      <TextBlock>Included</TextBlock> 
      <ListBox x:Name="IncludedFooList" ItemsSource="{Binding IncludedFoos}"></ListBox> 
     </StackPanel> 
     <Button Margin="10" Click="Button_Click">Add selected</Button> 
     <StackPanel Orientation="Vertical"> 
      <TextBlock>Available</TextBlock> 
      <Listbox:FilteringListBox x:Name="AvailableFooList" ItemsSource="{Binding AvailableFoos}" FilteringCollection="{Binding IncludedFoos}"></Listbox:FilteringListBox> 
     </StackPanel>     
    </StackPanel>    
</StackPanel> 

這是我的自定義組件 - 目前僅持有依賴屬性:

public class FilteringListBox : ListBox 
{ 
    public static readonly DependencyProperty FilteringCollectionProperty = 
     DependencyProperty.Register("FilteringCollection", typeof(ObservableCollection<Foo>), typeof(FilteringListBox));             

    public ObservableCollection<Foo> FilteringCollection 
    { 
     get 
     { 
      return (ObservableCollection<Foo>)GetValue(FilteringCollectionProperty); 
     } 
     set 
     { 
      SetValue(FilteringCollectionProperty, value); 
     } 
    } 
} 

而且完整的代碼後面的代碼和類定義在這裏:

public partial class MainWindow : Window 
{ 
    private MainViewModel _vm; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     _vm = new MainViewModel(); 
     DataContext = _vm; 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (AvailableFooList.SelectedItem == null) 
      return; 
     var selectedFoo = AvailableFooList.SelectedItem as Foo; 
     _vm.IncludedFoos.Add(selectedFoo); 
    } 
} 

public class MainViewModel 
{ 
    public MainViewModel() 
    { 
     IncludedFoos = new ObservableCollection<Foo>(); 
     AvailableFoos = new ObservableCollection<Foo>(); 
     GenerateAvailableFoos(); 
    } 

    private void GenerateAvailableFoos() 
    { 
     AvailableFoos.Add(new Foo { Text = "Number1" }); 
     AvailableFoos.Add(new Foo { Text = "Number2" }); 
     AvailableFoos.Add(new Foo { Text = "Number3" }); 
     AvailableFoos.Add(new Foo { Text = "Number4" }); 
    } 

    public ObservableCollection<Foo> IncludedFoos { get; set; } 
    public ObservableCollection<Foo> AvailableFoos { get; set; } 
} 

public class Foo 
{ 
    public string Text { get; set; } 
    public override string ToString() 
    { 
     return Text; 
    } 
} 

我向FilteringListBox中的DependencyProperty FilteringCollection的setter和getter添加斷點,但它從不觸發。爲什麼?我該如何解決它?

回答

5

綁定系統繞過設置並獲取依賴項屬性的訪問器。如果要在依賴項屬性更改時執行代碼,則應該將PropertyChangedCallback添加到DependencyProperty定義中。

+1

+1。我希望它更簡單...創建DependancyProperties的一些更好的約定......但這是我們必須忍受的。 getter/setter對開發人員來說只是一種方便,但對數據綁定沒有任何意義。實際上是相反的。該綁定系統調用'GetValue'和'SetValue',並且該屬性只是沒有約束地執行它。當調用SetValue時,事件被觸發。這很糟糕。 – 2010-09-08 13:55:08

+0

嗯..不是非常直觀或方便,但修復它。謝謝! – stiank81 2010-09-09 07:07:16

1

MSDN有一段約Dependency Property Callbacks and Validation,您需要從MSDN

註冊 PropertyChangedCallback

public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register( "AquariumGraphic", typeof(Uri), typeof(AquariumObject), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnUriChanged) ) ); private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Shape sh = (Shape) d; sh.Fill = new ImageBrush(new BitmapImage((Uri)e.NewValue)); } 
1

get和set屬性永遠不會被WPF框架直接使用。你只提供它們作爲你自己的方便。相反,您需要將回調添加到您的依賴項屬性註冊。當一個值綁定到依賴屬性時,回調將被調用。因此,您的FilteredListBox代碼應改爲類似如下的內容:

public partial class FilteringListBox : ListBox 
{ 
    public static readonly DependencyProperty FilteringCollectionProperty = 
     DependencyProperty.Register("FilteringCollection", typeof(ObservableCollection<Foo>), typeof(FilteringListBox), 
     new PropertyMetadata(null, FilteringCollectionPropertyCallback)); 

    static void FilteringCollectionPropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     FilteringListBox listbox = d as FilteringListBox; 
     // Do some work here 
    } 

    public ObservableCollection<Foo> FilteringCollection 
    { 
     get 
     { 
      return (ObservableCollection<Foo>) GetValue(FilteringCollectionProperty); 
     } 
     set 
     { 
      SetValue(FilteringCollectionProperty, value); 
     } 
    } 
} 
+0

你意識到默認值是靜態保存的,在這種情況下是通過引用來使用的?除非重寫值,否則每個FilteringListBox現在將默認引用ObservableCollection的相同實例。 – Bubblewrap 2010-09-08 13:52:52

+0

好點。在這種情況下,默認值是不必要的。它正被視圖模型的綁定覆蓋。 – 2010-09-08 14:15:34