开发者

Restricting WPF ComboBox choices from a known list

I'm developing a WPF user control that contains a ComboBox. The ComboBox choices are units of time, i.e. seconds, minutes, hours, days, etc. and are provided via a database lookup table. Each choice is tied to a corresponding enum value available from an enum called TimeInterval. Other features of our application will make decisions based o开发者_开发问答n the choice selected.

Developers using this control need to be able to limit which units of time are available as choices. For example, in certain circumstances it may only be appropriate to show minutes and seconds in the list. Other developers may want to provide the entire list.

I'm trying to come up with an elegant way of doing this, but am at a loss. My first thought was to somehow use Flags (FlagsAttribute) over an enum, but I wasn't sure how to approach it.

A pure XAML approach would be ideal, but I'm open to code solutions as well.

Thanks in advance.


You could use advantages of CollectionView to achieve expected behaviour.

In such scenario your UserControl exposes FilterTimeInterval dependency property, which type is Predicate<TimeInterval>. When this property is changed, you set up ICollectionView.Filter property for collection of your items. If third-party developer uses your control and desires to restrict combobox items, he should just bind appropriate predicate to FilterTimeInterval property.

Here is some demonstration (in order to simplify coding, combobox contains string items).

XAML of your control:

<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>

Code behind of your control with dependency property declaration:

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 of your control:

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;
        }
    }
}

Control is ready, it's time to use it and restrict some items. In this example I block every item except "Days".

Usage of your control in XAML looks like:

<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>

And of course we should prepare JustDaysFilter property in view model:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜