从已知列表中限制WPF ComboBox选项

时间:2011-05-02 21:09:29

标签: wpf combobox binding filtering

我正在开发一个包含ComboBox的WPF用户控件。 ComboBox选项是时间单位,即秒,分钟,小时,天等,并通过数据库查找表提供。每个选项都与一个名为TimeInterval的枚举中可用的相应枚举值相关联。我们的应用程序的其他功能将根据所选的选项做出决定。

使用此控件的开发人员需要能够限制哪些时间单位可供选择。例如,在某些情况下,仅在列表中显示分钟和秒可能是合适的。其他开发人员可能希望提供整个列表。

我正试图想出一个优雅的方式来做这件事,但我不知所措。我的第一个想法是以某种方式在枚举上使用Flags(FlagsAttribute),但我不确定如何接近它。

纯XAML方法是理想的,但我也对代码解决方案持开放态度。

提前致谢。

1 个答案:

答案 0 :(得分:1)

您可以使用CollectionView的优势来实现预期的行为。

在这种情况下,UserControl会公开FilterTimeInterval依赖项属性,该类型为Predicate<TimeInterval>。更改此属性后,您可以设置ICollectionView.Filter属性以收集项目。如果第三方开发人员使用您的控件并希望限制组合框项目,他应该将适当的谓词绑定到FilterTimeInterval属性。

这是一些演示(为了简化编码,组合框包含字符串项)。

你控制的XAML:

<UserControl x:Class="Test.TimeIntervalsControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ComboBox ItemsSource="{Binding Items}"/>
    </Grid>
</UserControl>

使用依赖项属性声明控制代码:

public partial class TimeIntervalsControl : UserControl
{
    public TimeIntervalsControl()
    {
        InitializeComponent();
        this.Model = new TimeIntervalsViewModel();
    }

    public TimeIntervalsViewModel Model
    {
        get
        {
            return (TimeIntervalsViewModel)this.DataContext;
        }
        set
        {
            this.DataContext = value;
        }
    }

    public Predicate<string> FilterTimeInterval
    {
        get
        {
            return (Predicate<string>)this.GetValue(TimeIntervalsControl.FilterTimeIntervalProperty);
        }
        set
        {
            this.SetValue(TimeIntervalsControl.FilterTimeIntervalProperty, value);
        }
    }

    public static readonly DependencyProperty FilterTimeIntervalProperty =
        DependencyProperty.Register("FilterTimeInterval",
            typeof(Predicate<string>),
            typeof(TimeIntervalsControl),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None,   
                (d, e) =>
                {
                    var control = (TimeIntervalsControl)d;
                    var view = CollectionViewSource.GetDefaultView(control.Model.Items);
                    if (e.NewValue == null)
                    {
                        view.Filter = null;
                    }
                    else
                    {
                        view.Filter = o => ((Predicate<string>)e.NewValue)((string)o);
                    }
                }));
}

您的控件的ViewModel:

public sealed class TimeIntervalsViewModel : ObservableObject
{
    private readonly string[] _items = new string[] {"Years","Month","Days","Hours","Minutes","Seconds"};

    public IEnumerable<string> Items
    {
        get
        {
            return this._items;
        }
    }
}

控制准备就绪,是时候使用它并限制一些项目了。在这个例子中,我阻止除“Days”之外的所有项目。

在XAML中使用控件如下:

<UserControl x:Class="Test.StartupView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:self="clr-namespace:Test"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="Root">
    <WrapPanel>
        <self:TimeIntervalsControl FilterTimeInterval="{Binding Path=DataContext.JustDaysFilter, ElementName=Root}"/>
    </WrapPanel>
</UserControl>

当然,我们应该在视图模型中准备JustDaysFilter属性:

public class StartupViewModel
{
    private readonly Predicate<string> _justDaysFilter = s => s == "Days";
    public Predicate<string> JustDaysFilter
    {
        get
        {
            return this._justDaysFilter;
        }
    }
}