2010-09-08 55 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