Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ComboBox Hide (Disable) DropDown Button Programmatically

Tags:

c#

combobox

wpf

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 :).

like image 210
Artur Szymański Avatar asked Oct 02 '22 23:10

Artur Szymański


1 Answers

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.

like image 92
Anatoliy Nikolaev Avatar answered Oct 13 '22 10:10

Anatoliy Nikolaev