我的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,但它永远不会被触发。为什么?我该如何解决?
答案 0 :(得分:5)
绑定系统绕过set并获取依赖项属性的访问器。如果要在依赖项属性更改时执行代码,则应向PropertyChangedCallback
定义添加DependencyProperty
。
答案 1 :(得分:1)
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));
}
答案 2 :(得分:1)
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);
}
}
}