如何对WPF ComboBox进行子类化以添加额外的按钮

3

我看到了一个类似的问题,希望能找到解决方案,但仅仅给出子类化ComboBox的建议对我来说还不够。我需要更具体的指导...

我的情况是我需要在我的特殊comboBox上添加一个额外的按钮,用于向项目列表中添加新记录。今天我已经将其作为UserControl实现,但它看起来不好,并且我需要在我的视图上添加更多控件,因此我开始制作自定义控件,尝试扩展ComboBox。

但我没有做得很远...请帮帮我... :)

目前我的代码如下:

public class ComboBoxWithAdd : ComboBox
{
    static ComboBoxWithAdd()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ComboBoxWithAdd), new FrameworkPropertyMetadata(typeof(ComboBoxWithAdd)));
    }
}

在Generic.xaml中,我有以下内容:
<Style TargetType="{x:Type local:ComboBoxWithAdd}" BasedOn="{StaticResource {x:Type ComboBox}}">        
</Style>

实际上,这听起来更适合使用自定义控件而不是 ComboBox 的子类。您能详细解释一下为什么选择这种方法并放弃增强自定义控件吗?那么子类化自定义控件呢? - FrustratedWithFormsDesigner
@沮丧 - 你从ComboBox派生的类是一个自定义控件。你在建议什么? - John Bowen
@John Bowen:抱歉,更具体地说:我指的是一个自定义控件,它是Control类的子类,并且其外观和布局是通过表单设计器进行操作的。如果我没记错的话,VisualStudio通常将这些类称为UserControls。 - FrustratedWithFormsDesigner
@沮丧:我已经尝试了UserControl路线,但我想要进一步改进。对我来说,自定义控件更加简洁,也更能够完全替代标准ComboBox。是的,我可以在我的用户控件中公开ComboBox的所有属性和事件,但老实说,那似乎需要很多工作。 - rozon
@Frustrated - UserControls是从UserControl派生的类,通常由XAML和代码后备文件组成,它们是彼此的部分类,并在运行时一起编译。您也可以使用其他控件类型来执行此操作,但这不太常见。它们很容易在设计器中加载和更改,但失去了很多灵活性,例如重新模板化的能力。自定义控件通常指任何从Control或其后代派生的类,并通过ControlTemplate与其UI松散链接,甚至可以在运行时更改。 - John Bowen
3个回答

4
当决定创建自定义控件时,您需要确定是否需要添加实际行为或仅UI。仅添加按钮可以通过自定义ControlTemplate来完成。听起来像是您想要一个按钮,该按钮会导致更新ComboBox的Items的操作,这将指向您从ComboBox派生控件的方向。您需要在代码和XAML方面添加一些内容。在您的样式中,您需要添加一个Setter用于ControlTemplate,并以ComboBox的默认模板副本开始(我通常使用Blend进行此操作,但还有其他来源)。然后您可以在模板中任何位置添加新的按钮。
<Style TargetType="{x:Type local:ComboBoxWithAdd}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ComboBoxWithAdd}">
                ... copy of default template with your modifications
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

连接按钮的方法有几种,但最可靠的是使用可以在控制代码中绑定的命令。您可以稍后在控制代码中声明自己的RoutedCommand,但为了开始,只需使用内置的命令。

public ComboBoxWithAdd()
{
    CommandBindings.Add(new CommandBinding(ApplicationCommands.New, NewExecutedMethod));
}

接着,在NewExecutedMethod中添加任何逻辑,以执行添加项目的实际操作(可能涉及ComboBox的Items/ItemsSource)。要连接按钮,只需设置Command="ApplicationCommands.New"。可以用自定义控件做更多事情,但这应该可以让你开始。


我认为这是我能得到的最好答案,但我意识到ComboBox模板对我来说太复杂了。我不会放弃,但会继续做其他事情,并在以后再尝试一次。 - rozon
rozong,请看下面我的回答。 - Falcon

1
Rozon,您可以在代码后端像这样操作Combobox,而无需创建复杂的模板:
public class CustomComboBox : ComboBox
{
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        Grid grid = WpfHelper.FindAllChildrenByName<Grid>(this, "MainGrid").SingleOrDefault() as Grid;
        if (grid != null)
        {
            grid.ColumnDefinitions.Add(new ColumnDefinition());
            Button button = new Button();
            button.Content = "test";
            button.SetValue(Grid.ColumnProperty, 2);
            grid.Children.Add(button);
        }
    } 
}

WpfHelper只是一个通过名称查找可视化子元素的类。请注意,如果组合框的标准控件模板被更改并且MainGrid被重命名,则这可能很容易出现问题。


很棒。我之前不知道WpfHelper。我可以看出这个很容易出问题,但我也能想到其他几个用途。谢谢! :) - rozon
1
如果您无法访问WpfHelper,我认为您也可以执行以下操作:var grid = GetTemplateChild("MainGrid") as Grid; - Jerod Houghtelling

0

我建议您使用UserControl,通过添加一个按钮并将它们分组来创建一个用户控件,并公开所需的事件和命令。

不建议使用自定义控件。

但是,如果您有这样的要求。我们可以这样做: 1)您需要为您尝试扩展功能的控件派生控件。 2)您需要为控件创建默认模板。[Generic.Xaml]

其余的就是您的自定义。 但是,一个优点是您可以获得一个易于皮肤化的控件。

希望对您有所帮助


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