none
ComboBox SelectedIndex property binding

    Question

  •  

    Hello,

    I have a combo box populate with a list of strings, and I would like to bind the SelectedIndex Property to the Index property of object Source.

     

    Look at the example below:

     

    Code Block

    public class Source : INotifyPropertyChanged

        {

            private int index;

            public int Index

            {

                get { return this.index; }

                set

                {

                    if (this.index != value)

                    {

                        this.index = value;

                        if (this.PropertyChanged != null)

                            this.PropertyChanged(this, new PropertyChangedEventArgs("Index"));

                    }

                }

            }

            public event PropertyChangedEventHandler PropertyChanged;

        }

     

     

    It works well, the combobox index changes when I modify Source.Index and viceversa.

     

    The problem happens when I would like to add a custom behavior to the ComboBox. I want that the user is not able to select manually an item called "Undefined" that has index 0.

     

    For this reason, in the Source.Index setter property if value is 0 I don't store the it to the field index.

     

    Unfortunately this implementation does not work and the modification that I do is not reflected to the UI, and then hte user is able to select the item "Undefined".

     

    Code Block

    public class Source : INotifyPropertyChanged

        {

            private int index;

            public int Index

            {

                get { return this.index; }

                set

                {

                    if (this.index != value)

                    {

       // do not allow the user to select the first item of the list

       if (value <> 0)

       this.index = value;

     

                        if (this.PropertyChanged != null)

                            this.PropertyChanged(this, new PropertyChangedEventArgs("Index"));

                    }

                }

            }

            public event PropertyChangedEventHandler PropertyChanged;

        }

     

     

    Can you help we to find a workaround for this problem?

     

    thanks

    Marco

    Wednesday, January 23, 2008 8:16 AM

Answers

  • I think as long as you know what constitutes a invalid enum value (for instance "Undefined"), you should be able to use custom IValueConverter to do the trick, basically you could bind the enum value to ComboBoxItem's IsEnabled property, and inside the IValueConverter implementation, you could check if the current enum value is an valid value, if it is, you could simply return true otherwise return false as the following example shows:

    Code Snippet
    <Window x:Class="AnswerHarness.BindToEnumDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:AnswerHarness"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="BindToEnumDemo" Height="300" Width="300">
    <
    Window.Resources>
    <
    local:InvalidValueConverter x:Key="converter"/>
    <
    ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="odp">
    <
    ObjectDataProvider.MethodParameters>
    <
    x:Type TypeName="local:MyEnum"/>
    </
    ObjectDataProvider.MethodParameters>
    </
    ObjectDataProvider>
    </
    Window.Resources>

    <
    Border Margin="30" BorderBrush="Blue" BorderThickness="2" Padding="10">
    <
    ComboBox ItemsSource="{Binding Source={StaticResource odp}}" Height="23">
    <
    ComboBox.ItemContainerStyle>
    <
    Style TargetType="{x:Type ListBoxItem}">
    <
    Setter Property="Content" Value="{Binding}"/>
    <
    Setter Property="IsEnabled" Value="{Binding Converter={StaticResource converter}}"/>
    </
    Style>
    </
    ComboBox.ItemContainerStyle>
    </
    ComboBox>
    </
    Border>
    </
    Window>
    public class InvalidValueConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    String strValue = value.ToString();
    if (strValue == "Undefined")
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    throw new NotImplementedException();
    }
    }

    public enum MyEnum
    {
    Value1,
    Value2,
    Undefined,
    Value3
    }

    Hope this helps
    Friday, January 25, 2008 4:18 AM
  • Here is the C# version of the XAML code:

    Code Snippet
    public BindToEnumDemo()
    {
    InitializeComponent();
    comboBox.ItemContainerStyle = CreateItemContainerStyle();
    }

    private Style CreateItemContainerStyle()
    {
    Style style = new Style();
    Setter contentSetter = new Setter();
    contentSetter.Property = ComboBoxItem.ContentProperty;
    contentSetter.Value = new Binding();
    style.Setters.Add(contentSetter);
    Setter isEnabledSetter = new Setter();
    isEnabledSetter.Property = ComboBoxItem.IsEnabledProperty;
    Binding isEnabledBinding = new Binding();
    isEnabledBinding.Converter = new InvalidValueConverter();
    isEnabledSetter.Value = isEnabledBinding;
    style.Setters.Add(isEnabledSetter);
    return style;
    }

    I have to say it's not a fun process to write this type of code using C#, that's why XAML is invented

    Hope this helps

    Friday, January 25, 2008 8:25 AM

All replies

  • Have you tried setting 'IsEnabled' to false for the combo boxes that can't be selected?
    Wednesday, January 23, 2008 8:53 AM
  • I don't want to Disable the combo box but I want to block the user to select a "specific" item of a combo box

     

    Wednesday, January 23, 2008 11:07 AM
  • My appologies, I meant comboBoxItems.  If the items you don't want the user to select are disabled, this should also do the trick right?

    If the comboBoxItems are generated (you don't define them in xaml) you might need to use an ItemsContainerStyleSelector to get the correct style.

    Wednesday, January 23, 2008 12:15 PM
  • now I understand your suggestion, thanks. Unfortunately I cannot implement it. I will try to explain you why..

     

    I am developing an IDE that has a TreeView and a PropertyGrid. As you know in WPF we don't have a PropertyGrid component, and I don't want to use the one provided with Windows.Forms. So I decided to create my own.

     

    The TreeView is binded to a custom class that derives from ObservableCollection and contains a collection of TreeNode.

     

    Class TreeNode

    Inherits ObservableCollection(Of TreeNode)

     

    End Class

     

    When the user select a node in the TreeView I populate the PropertyGrid with the content of object TreeNode.

    For each property of object, based on the type of that property, I populate the PropertyGrid accordingly: for example if I have a String property I create a TextBox, if I have an Enumeration I create a ComboBox, etc.

     

    The PropertyGrid doesn't know anything of the business logic implemented by the object TreeNode.

     

    For this reason I cannot set the specific item ReadOnly property of the ComboBox. Is it clearer now what I am trying to do?

     

     

    Wednesday, January 23, 2008 1:07 PM
  • I think as long as you know what constitutes a invalid enum value (for instance "Undefined"), you should be able to use custom IValueConverter to do the trick, basically you could bind the enum value to ComboBoxItem's IsEnabled property, and inside the IValueConverter implementation, you could check if the current enum value is an valid value, if it is, you could simply return true otherwise return false as the following example shows:

    Code Snippet
    <Window x:Class="AnswerHarness.BindToEnumDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:AnswerHarness"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="BindToEnumDemo" Height="300" Width="300">
    <
    Window.Resources>
    <
    local:InvalidValueConverter x:Key="converter"/>
    <
    ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="odp">
    <
    ObjectDataProvider.MethodParameters>
    <
    x:Type TypeName="local:MyEnum"/>
    </
    ObjectDataProvider.MethodParameters>
    </
    ObjectDataProvider>
    </
    Window.Resources>

    <
    Border Margin="30" BorderBrush="Blue" BorderThickness="2" Padding="10">
    <
    ComboBox ItemsSource="{Binding Source={StaticResource odp}}" Height="23">
    <
    ComboBox.ItemContainerStyle>
    <
    Style TargetType="{x:Type ListBoxItem}">
    <
    Setter Property="Content" Value="{Binding}"/>
    <
    Setter Property="IsEnabled" Value="{Binding Converter={StaticResource converter}}"/>
    </
    Style>
    </
    ComboBox.ItemContainerStyle>
    </
    ComboBox>
    </
    Border>
    </
    Window>
    public class InvalidValueConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    String strValue = value.ToString();
    if (strValue == "Undefined")
    {
    return false;
    }
    else
    {
    return true;
    }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    throw new NotImplementedException();
    }
    }

    public enum MyEnum
    {
    Value1,
    Value2,
    Undefined,
    Value3
    }

    Hope this helps
    Friday, January 25, 2008 4:18 AM

  • Thank you Marco, it helps me a lot.

     

    Now I understood the logic, but can you help me in translating the declarative code

     

    <ComboBox.ItemContainerStyle>
            <
    Style TargetType="{x:Type ListBoxItem}">
              <
    Setter Property="Content" Value="{Binding}"/>
              <
    Setter Property="IsEnabled" Value="{Binding Converter={StaticResource converter}}"/>
            </
    Style>
          </
    ComboBox.ItemContainerStyle>

    into code behind code (C# or VB.NET) is the same. Because I am adding the ComboBox controls plus other control at runtime.

     

    Thank you again,

    Marco Ragogna

    Friday, January 25, 2008 7:46 AM
  • Here is the C# version of the XAML code:

    Code Snippet
    public BindToEnumDemo()
    {
    InitializeComponent();
    comboBox.ItemContainerStyle = CreateItemContainerStyle();
    }

    private Style CreateItemContainerStyle()
    {
    Style style = new Style();
    Setter contentSetter = new Setter();
    contentSetter.Property = ComboBoxItem.ContentProperty;
    contentSetter.Value = new Binding();
    style.Setters.Add(contentSetter);
    Setter isEnabledSetter = new Setter();
    isEnabledSetter.Property = ComboBoxItem.IsEnabledProperty;
    Binding isEnabledBinding = new Binding();
    isEnabledBinding.Converter = new InvalidValueConverter();
    isEnabledSetter.Value = isEnabledBinding;
    style.Setters.Add(isEnabledSetter);
    return style;
    }

    I have to say it's not a fun process to write this type of code using C#, that's why XAML is invented

    Hope this helps

    Friday, January 25, 2008 8:25 AM
  •  

    First of all thank you work the answer and for supporting hardly this forum. It works perfectly

     

    I have understood that modify controls via code is more complex than using XAML, but what can I do if I need to add many controls at runtime and change their properties (in particular its binding) according to some business logic?

     

    You are an expert so I would like to ask you if it is the right approach, or do you think that is better to create a User Control for each type I have to manage.

     

    e.g.  ComboBoxEnum to manage enumerations

           TextBoxNumeric to manage numeric types

     

    Friday, January 25, 2008 10:42 AM
  • sorry for the post but I was looking for an answer to a databinding issue and found this post - I'm trying to bind a custom object property to a combo box so that when the selected index changes the porperty value chnages and the ProperyChanged event is fired but I cannot get the link to work.  You mention you have made this link.  Could you post your code for binding the data please?

    My code which is not working is:

    comboBox1.DataBindings.Add("SelectedItemValue", _TeleconferencingInfo, "MyProperty");

    Many Thanks

    Wednesday, November 19, 2008 9:50 AM