0

I'm trying to learn some data-binding in WPF, so have started building a little condition builder test application, but am having some trouble figuring out my binding.

So I have a set of conditions that are based upon generics. This is the class structure with just a simple example of a BooleanCondition.

public abstract class AbstractCondition
{
    /// <summary>
    /// Gets the entry mode.
    /// </summary>
    /// <value>The entry mode.</value>
    public abstract InputFieldMode InputFieldMode { get; }
}

public abstract class GenericCondition<T, O> : AbstractCondition
{
    /// <summary>
    /// Checks the specified value.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public abstract Boolean Check(T value);

    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    /// <value>The value.</value>
    public object Value
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the options.
    /// </summary>
    /// <value>The options.</value>
    public O Option
    {
        get;
        set;
    }

    /// <summary>
    /// Gets the available options.
    /// </summary>
    /// <value>The available options.</value>
    public abstract ObservableCollection<O> AvaliableOptions { get; }
}

/// <summary>
/// Describes a Condition that operations on a Boolean
/// </summary>
/// <typeparam name="U"></typeparam>
public class BooleanCondition : GenericCondition<Boolean?, BooleanConditionOption>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="BooleanCondition&lt;U&gt;"/> class.
    /// </summary>
    /// <param name="option">The option.</param>
    public BooleanCondition(BooleanConditionOption option)
    {
        this.Option = option;
    }

    /// <summary>
    /// Checks the specified value.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public override bool Check(bool? value)
    {
        if (value.HasValue)
        {
            switch (this.Option)
            {
                case BooleanConditionOption.IsFalse:
                    return !value.Value;

                case BooleanConditionOption.IsTrue:
                    return value.Value;
            }
        }

        return false;
    }

    /// <inheritdoc />
    public override InputFieldMode InputFieldMode
    {
        get { return InputFieldMode.NoField; }
    }

    /// <inheritdoc />
    public override ObservableCollection<BooleanConditionOption> AvaliableOptions
    {
        get
        {
            var options = Enum.GetValues(typeof(BooleanConditionOption));
            var optionsCollection = new ObservableCollection<BooleanConditionOption>(options.Cast<BooleanConditionOption>());
            return optionsCollection;
        }
    }
}

There are 4 Conditions currently, the basic idea behind this, is that a Condition operates on a type of Object, and provides a set of 'ConditionOptions' that are particular for that type (Bool has isTrue, isFalse, whereas a number might have < <= > >= etc).

So now I'm trying to create a view to make the Condition easier to consume on the UI. An Update is called with a selected value from a combo, that has a datatype. At that point I construct the appropriate condition, and want to expose a collection of ConditionOptions via the ConditionValues property (so the results of an enum, but it could be anyone of 4).

public class ConditionView
    {
        /// <summary>
        /// Gets the Fields that are available for selection.
        /// </summary>
        public ObservableCollection<IDataField> Fields { get; set; }

        public ObservableCollection<Object> ConditionValues { get; set; }

        /// <summary>
        /// Gets the Condition that has been selected.
        /// </summary>
        public AbstractCondition SelectedCondition { get; private set; }

        /// <summary>
        /// Update various options based upon the Selection
        /// </summary>
        /// <param name="field">The IDataField selected</param>
        public void Update(IDataField field)
        {
            if (field != null)
            {
                // Determine what sort of condition we need
                switch (field.Type)
                {
                    case DataType.Boolean:
                        BooleanCondition booleanCondition = new BooleanCondition(BooleanConditionOption.IsFalse);
                        this.SelectedCondition = booleanCondition;
                        this.ConditionValues = booleanCondition.AvaliableOptions;
                        break;

                    case DataType.String:
                        this.SelectedCondition = new StringCondition(StringConditionOption.Contains);
                        break;

                    case DataType.Numeric:
                        this.SelectedCondition = new NumericCondition(NumericConditionOption.Equals);
                        break;

                    case DataType.Date:
                        this.SelectedCondition = new DateCondition(DateConditionOption.Equals);
                        break;

                    default:
                        throw new InvalidOperationException("Unknown Data Type");
                }
            }
        }

I'm currently just trying to get the Boolean one going, but I'm not sure if ObservableCollection is what I should be binding to (I get a build error trying: "Error 5 Cannot implicitly convert type 'System.Collections.ObjectModel.ObservableCollection' to 'System.Collections.ObjectModel.ObservableCollection'). How should I be approaching this binding issue? Ultimately I've got some Convertors that are going to expect to be working on an enum too, so I'm not sure just casting the results to Objects is right :S

Update:

Trying to bind 'Fields' to a ComboBox, and once it varies a call through to Update will modify 'ConditionValues' which is bound to another ComboBox.

<UserControl x:Class="ConditionBuilder.Views.Condition"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             xmlns:cb="clr-namespace:ConditionBuilder"
             xmlns:wm="clr-namespace:Watermark"
             >
    <UserControl.Resources>
        <cb:EnumToUIConvertor x:Key="enumItemsConverter"/>
    </UserControl.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="229"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <ComboBox x:Name="cmbField" Grid.Column="0" Height="22" Width="120" ItemsSource="{Binding Path=Fields}" SelectionChanged="cmbField_SelectionChanged"> 
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding Path=Name, Mode=OneWay}" Height="Auto" Margin="-5" VerticalAlignment="Stretch"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
             <wm:Watermark.WatermarkContent>
                <Label Padding="0">Select Field...</Label>
            </wm:Watermark.WatermarkContent>
        </ComboBox>
        <ComboBox x:Name="cmbCondition" Grid.Column="1" Height="22" Width="120" ItemsSource="{Binding Path=ConditionValues, Mode=OneWay}">
            <wm:Watermark.WatermarkContent>
                <Label Padding="0">Select Condition...</Label>
            </wm:Watermark.WatermarkContent>
        </ComboBox>           
    </Grid>
</UserControl>
2
  • I'm not sure what exactly you're trying to bind. Can you post the relevant XAML? Commented May 20, 2011 at 16:01
  • Sure, updated the question and tried to make it clearer. It's my 'ConditionValues' that could contain values from 1 of 4 different enums. Commented May 20, 2011 at 16:05

1 Answer 1

1

I think I understand now. You could probably bind to SelectedCondition.AvailableOptions and do away with ConditionValues altogether. However, I don't see any INotifyPropertyChanged in your code so unless you're using notifypropertyweaver or some other trick, you will probably need to make SelectedCondition raise a property changed event.

Sign up to request clarification or add additional context in comments.

1 Comment

Actually, that's a really good point. I was concerned before because to get things compiling I had to cast my Enumerable to an IEnumerable<Object> and didn't think the binding would quite work. Actually it did. But removing the property completely sounds like a much better idea. Not yet read up on the INotifyPropertyChanged, so will have a delve into that. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.