Почему мое свойство зависимости не устанавливается при привязке к нему? - PullRequest
3 голосов
/ 08 сентября 2010

В моем приложении WPF отображаются две коллекции, и я хотел бы отключить элементы одной из них в другой. Делая это, я создаю пользовательский элемент управления FilteringListBox, который наследует ListBox, и я хочу добавить некоторую обработку внутри него, чтобы отключить элементы, которые установлены в наборе наборов через свойство на 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;
    }
}

Я добавляю точки останова к установщику и получателю объекта FilteringCollection DependencyProperty в FilteringListBox, но он никогда не срабатывает. Зачем? Как я могу это исправить?

Ответы [ 3 ]

5 голосов
/ 08 сентября 2010

Система привязки обходит установленные и получающие методы доступа для свойств зависимостей.Если вы хотите выполнить код при изменении свойства зависимости, вы должны добавить PropertyChangedCallback к определению DependencyProperty.

1 голос
/ 08 сентября 2010

Свойства 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);
        }
    }
}
1 голос
/ 08 сентября 2010

В MSDN есть раздел о Обратные вызовы и проверка свойств зависимостей , вам необходимо зарегистрировать 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));
}
...