5
votes

I would like to know how to disable ComboBox DropDown Button Programmatically. I had seen many similar subjects but all of these have a XAML solution.

By the way, if someone know how to disable all ComboBox control design and left visible only item template it can be helpful too.

UPDATE

its my XAML definition

<ComboBox Name="lang_ComboBox" SelectionChanged="LanguageSelection_ComboBox_SelectionChanged"/>

And there is how i use it:

String text = "dorf";
BitmapImage image = new BitmapImage(new Uri("http://img88.imageshack.us/img88/4351/butchermi4.png"));
lang_ComboBox.Width = 100;
lang_ComboBox.Height = 30;
Grid sp;
for (int i = 0; i < 5; i++)
{
    ColumnDefinition gridCol1 = new ColumnDefinition();
    gridCol1.Width = new GridLength(30.0);
    ColumnDefinition gridCol2 = new ColumnDefinition();
    gridCol2.Width = new GridLength(70.0);
    sp = new Grid()
    {
        Width = 100,
        Height = 30
    };
    Image im = new Image()
    {
        Source = image,
        Width = 25,
        Height = 25
    };
    Label la = new Label() 
    { 
        Content = text
    };
    sp.ColumnDefinitions.Add(gridCol1);
    sp.ColumnDefinitions.Add(gridCol2);
    Grid.SetColumn(im, 0);
    Grid.SetColumn(la, 1);
    sp.Children.Add(la);
    sp.Children.Add(im);
    lang_ComboBox.Items.Add(sp);
}

UPDATE 2 Hmmm I get it now, I use wrong word. It should be "Hide" control design and still can choose from a list. My bad sorry. But i know how i can solve it with Anatoliy Nokolaev's Code. To hide control design i use:

ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(lang_ComboBox);
dropDownButton.Visibility = System.Windows.Visibility.Collapsed;

Unwanted behavior is now only that i cant show combobox dropdownmenu, but I'll invoke it programmatically by add on click event and should be good.

If there is any easiest way to do this tell me :).

2
I can give you a more simple solution, but it will depend on the ComboBox template, which you arrange it? If yes, then I can give an example of it in the answer.Anatoliy Nikolaev
@Anatoliy Nikolaev I always want to learn something new, then sure show it :)Artur Szymański
Okay, give me time and I'll show you.Anatoliy Nikolaev

2 Answers

4
votes

To disable only the ToggleButton in ComboBox programmatically, you need to find this in the ComboBox control using VisualTreeHelper and assign a property IsEnabled to false, like this:

XAML

<Window x:Class="DisableComboBoxButton.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    Loaded="Window_Loaded">

    <StackPanel>
        <ComboBox Name="comboBox"
                  Width="100" 
                  Height="25"
                  SelectedIndex="0">

            <ComboBoxItem>Test1</ComboBoxItem>
            <ComboBoxItem>Test2</ComboBoxItem>
            <ComboBoxItem>Test3</ComboBoxItem>
        </ComboBox>

        <ComboBox Name="AllComboBoxDisabled"
                  Width="100" 
                  Height="25"
                  IsEnabled="False"
                  SelectedIndex="0">

            <ComboBoxItem>Test1</ComboBoxItem>
            <ComboBoxItem>Test2</ComboBoxItem>
            <ComboBoxItem>Test3</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>

Code-behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(comboBox);

        dropDownButton.IsEnabled = false;
    }

    public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        if (dependencyObject == null)
        {
            return null;
        }

        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            var child = VisualTreeHelper.GetChild(dependencyObject, i);

            var result = (child as T) ?? GetFirstChildOfType<T>(child);

            if (result != null)
            {
                return result;
            }
        }

        return null;
    }
}

Output

enter image description here

Notes

Always use GetFirstChildOfType() function only when the control will be fully loaded, otherwise it will not find it and give null. In this case, I put this code in the event Window_Loaded which says that all the controls of the Window successfully load.

Edit: another version

Not to say that this version is easier to implement, but it would be more correct and a bit easier to use.

So, we need a template for your ComboBox, because it allows access to elements that are within the control. Just like that, the ToggleButton can not be accessed from both the code and of XAML.

We create attached dependency property that will serve the current ComboBox another property, such as which will give access to our button Visibility.

Our property Visibility:

public static class ButtonExt
{
    public static readonly DependencyProperty VisibilityProperty;

    public static void SetVisibility(DependencyObject DepObject, Visibility value)
    {
        DepObject.SetValue(VisibilityProperty, value);
    }

    public static Visibility GetVisibility(DependencyObject DepObject)
    {
        return (Visibility)DepObject.GetValue(VisibilityProperty);
    }

    static ButtonExt()
    {
        PropertyMetadata VisibiltyPropertyMetadata = new PropertyMetadata(Visibility.Collapsed);

        VisibilityProperty = DependencyProperty.RegisterAttached("Visibility",
                                                            typeof(Visibility),
                                                            typeof(ButtonExt),
                                                            VisibiltyPropertyMetadata);
    }
}

Setter property in ComboBox template (skip version, full version see in project in App.xaml file):

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type ComboBox}">
            <Grid>
                <ToggleButton Name="ToggleButton" 
                              Template="{StaticResource ComboBoxToggleButton}" 
                              IsChecked="{Binding Path=IsDropDownOpen, 
                                                  Mode=TwoWay, 
                                                  RelativeSource={RelativeSource TemplatedParent}}" 
                              Visibility="{TemplateBinding PropertiesExtension:ButtonExt.Visibility}" // <------ Here
                              Grid.Column="2" 
                              Focusable="False"                        
                              ClickMode="Press" />

Now, we are setting this property like this:

<ComboBox Name="comboBox"
          Style="{StaticResource ComboBoxBaseStyle}"
          PropertiesExtension:ButtonExt.Visibility="Visible"
          Width="100"
          Height="30"
          SelectedIndex="0">

    <ComboBoxItem>Test1</ComboBoxItem>
    <ComboBoxItem>Test2</ComboBoxItem>
    <ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>

or in code-behind via Click event handlers:

private void HideButton_Click(object sender, RoutedEventArgs e)
{ 
    ButtonExt.SetVisibility(comboBox, Visibility.Hidden);
}

private void ShowButton_Click(object sender, RoutedEventArgs e)
{
    ButtonExt.SetVisibility(comboBox, Visibility.Visible);
}    

Full version of example project is here.

0
votes

Try with this

Dispatcher.BeginInvoke(new Action(() =>
            {
                ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(cboMedicos);
                if (dropDownButton != null)
                {
                    dropDownButton.IsEnabled = false;
                }

            }), System.Windows.Threading.DispatcherPriority.Render);




        public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
        {
            if (dependencyObject == null)
            {
                return null;
            }

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
            {
                var child = VisualTreeHelper.GetChild(dependencyObject, i);

                var result = (child as T) ?? GetFirstChildOfType<T>(child);

                if (result != null)
                {
                    return result;
                }
            }

            return null;
        }