【问题标题】:Restricting WPF ComboBox choices from a known list限制已知列表中的 WPF ComboBox 选项
【发布时间】:2011-05-02 21:09:28
【问题描述】:

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

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

我试图想出一种优雅的方式来做到这一点,但不知所措。我的第一个想法是在枚举上以某种方式使用 Flags (FlagsAttribute),但我不知道如何处理它。

纯 XAML 方法是理想的,但我也愿意接受代码解决方案。

提前致谢。

【问题讨论】:

  • 有什么理由不让控件的使用者提供用户可以选择的有效值列表?
  • 有一个规定的可用选项列表(在数据库查找表中提供)。每个选择都将与一个名为 TimeInterval 的枚举相关联,该枚举将用于在应用程序代码的其他区域做出决策。我们需要确保消费者遵守规定的清单。最坏的情况,我想我们可以让开发人员负责提供一个有效的列表。
  • 我想另一种方法可能是让开发人员有责任提供列表,然后让用户控件在运行时执行验证,或者可能在设计时执行以确保选择的有效列表是提供。

标签: wpf combobox binding filtering


【解决方案1】:

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

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

这里有一些演示(为了简化编码,combobox 包含字符串项)。

您的控件的 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;
        }
    }
}

【讨论】:

  • 谢谢亚历克斯,这很好用。我玩弄了将 TimeIntervalsControl 上的 ViewModel 设置为 DependencyProperty,这很有效,但您的解决方案似乎更干净。我还不确定这两种方法的优缺点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-28
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多