WPF ComboBox如何在程序中隐藏(禁用)下拉按钮?

5
我想知道如何以编程方式禁用ComboBox下拉按钮。我看到了许多类似的主题,但所有这些主题都有一个XAML解决方案。
顺便说一下,如果有人知道如何禁用所有ComboBox控件设计,并仅保留项目模板可见,那也可能会有所帮助。
更新
这是我的XAML定义
<ComboBox Name="lang_ComboBox" SelectionChanged="LanguageSelection_ComboBox_SelectionChanged"/>

这是我使用它的方式:
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);
}

更新2 嗯,我现在明白了,我用错了单词。它应该是“隐藏”控件设计,但仍然可以从列表中选择。我的错误,抱歉。但是我知道如何使用Anatoliy Nokolaev的代码解决这个问题。要隐藏控件设计,我使用:

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

现在不需要显示组合框下拉菜单,但我会通过添加点击事件来编程调用它,这是唯一的不希望出现的行为,应该没问题了。

如果有更简单的方法,请告诉我 :)。


我可以给你一个更简单的解决方案,但这将取决于ComboBox模板,你是如何安排它的?如果是的话,那么我可以在答案中给出一个示例。 - Anatoliy Nikolaev
@Anatoliy Nikolaev 我总是想学习新的东西,那么请展示吧 :) - Artur Szymański
好的,给我一点时间,我会向您展示。 - Anatoliy Nikolaev
2个回答

4
要在程序中仅禁用ComboBox中的ToggleButton,您需要使用VisualTreeHelperComboBox控件中找到它,并将属性IsEnabled赋值为false。操作如下:

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

输出

在此输入图片描述

注释

始终仅在控件完全加载时使用GetFirstChildOfType()函数,否则它将无法找到它并返回null。在这种情况下,我将此代码放在事件Window_Loaded中,该事件表示窗口的所有控件都已成功加载。

编辑:另一个版本

不是说这个版本更容易实现,但它会更正确一些,并且更容易使用。

因此,我们需要为您的ComboBox创建模板,因为它允许访问控件内部的元素。就像那样,ToggleButton不能从代码和XAML中都访问。

我们创建附加依赖属性,它将为当前ComboBox提供另一个属性,例如,它将访问我们的按钮可见性。

我们的属性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);
    }
}

ComboBox 模板中的 Setter 属性(跳过版本, 完整版本参见项目中的 App.xaml 文件):

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

现在,我们需要这样设置这个属性:

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

或者在代码后台通过单击事件处理程序:

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

这里有一个完整的示例项目,请点击此处


0

试试这个

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

虽然这段代码可能解决了问题,但是包括一个解释关于如何以及为什么解决这个问题将有助于提高您的发帖质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - Adrian Mole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接