代码之家  ›  专栏  ›  技术社区  ›  stiank81

绑定到依赖项属性时为什么不设置它?

  •  3
  • stiank81  · 技术社区  · 14 年前

    我的WPF应用程序中显示了两个集合,我希望其中一个的元素在另一个中被禁用。执行此操作时,我将创建一个继承列表框的自定义控件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,但它从未被触发。为什么?我怎么修?

    3 回复  |  直到 14 年前
        1
  •  5
  •   Bubblewrap    14 年前

    绑定系统绕过依赖属性的set和get访问器。如果要在依赖项属性更改时执行代码,则应添加 PropertyChangedCallback DependencyProperty 定义。

        2
  •  1
  •   Filip Ekberg    14 年前

    msdn有一个关于 Dependency Property Callbacks and Validation ,您需要注册 PropertyChangedCallback

    来自msdn的示例

    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));
    }
    
        3
  •  1
  •   Jakob Christensen    14 年前

    WPF框架从不直接使用get和set属性。你只提供它们作为你自己的方便。相反,您需要向依赖项属性注册添加回调。当值绑定到依赖项属性时,将调用回调。因此,您的代码 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);
            }
        }
    }