在代码中获取视图的所有组合框

时间:2015-06-12 16:20:25

标签: c# wpf

我正在尝试在加载视图后立即将所有组合框的大小调整为最长项目的宽度。我偶然发现了以下问题:在XAML中这是不可能的:How can I make a WPF combo box have the width of its widest element in XAML?

所以,现在我要做的是应用初始问题中找到的代码,并将其循环到我视图中的所有组合框。从我的视图背后的代码中,有没有办法获取其中包含的所有组合框,以便我可以遍历它们并调整它们的宽度,而不是手动为每个组合框执行它?

编辑:

建议的重复答案似乎不适用于UserControl类型视图。以下是我的视图代码的声明:

public partial class QuickLookRequestView : UserControl, IView<QuickLookRequestViewModel>
{
    private QuickLookRequestViewModel _viewModel;

    public QuickLookRequestView()
    {
        InitializeComponent();

        // This cannot be done in XAML
        ResizeComboBoxToMaxItemWidth();
    }

    private void ResizeComboBoxToMaxItemWidth()
    {
        foreach (ComboBox comboBox in FindVisualChildren<ComboBox>(this))
        {
            double width = 0;
            foreach (ComboBoxItem item in comboBox.Items)
            {
                item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                if (item.DesiredSize.Width > width)
                {
                    width = item.DesiredSize.Width;
                }   
            }
            comboBox.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            comboBox.Width = comboBox.DesiredSize.Width + width;
        }
    }

    private IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

    public QuickLookRequestViewModel ViewModel
    {
        get { return _viewModel; }
        set { _viewModel = value; }
    }
}

在调试时,应用程序永远不会进入代码的foreach (ComboBox comboBox in FindVisualChildren<ComboBox>(this))部分,因此它找不到我的组合框。

EDIT2:

似乎FindVisualChildren中的以下函数找不到我的UserControl的任何可视子项:for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)

EDIT3:

我的第一次和第二次编辑不再有问题,尽管我确实有一个新问题。我的一个组合框显示枚举中的项目。这样做是这样的:

<ComboBox Name="ItemTypeComboBox" Margin="10,5,5,5" ItemsSource="{Binding ComboBoxItemTypes}" SelectedItem="{Binding SelectedComboBoxItemType}"/>

ComboBoxItemTypesget属性定义如下:

public IEnumerable<EveItem.ItemTypes> ComboBoxItemTypes 
{
    get
    {
        return Enum.GetValues(typeof(EveItem.ItemTypes)).Cast<EveItem.ItemTypes>();
    }
}

SelectedComboBoxItemType的类型为ItemTypes,其定义方式如下:

public enum ItemTypes
{
    Ore,
    Ice,
    Gas,
    Mineral,
    Pi
}

我遇到的问题是,当FindVisualChildren()循环通过该组合框时,我收到以下错误消息:

Unable to cast object of type 'ItemTypes' to type 'System.Windows.Controls.ComboBoxItem'

如何修改FindVisualChildren()函数以使用我的组合框和枚举类型?

2 个答案:

答案 0 :(得分:0)

Form form = (your form, or control, or view, etc.)
IEnumerable<CheckBox> list = form.Controls.OfType<ComboBox>();
编辑:抱歉,我发现您使用的是WPF而不是Windows窗体,我不确定WPF的等效内容。

答案 1 :(得分:0)

我刚试过这个,它按预期工作:

public class CustomComboBox : ComboBox
{
    private int _selected;

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _selected = SelectedIndex;
        SelectedIndex = -1;
        Loaded += ComboBoxEx_Loaded;
    }

    void ComboBoxEx_Loaded(object sender, RoutedEventArgs e)
    {
        var popup = GetTemplateChild("PART_Popup") as Popup;
        var content = popup.Child as FrameworkElement;
        content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        MinWidth = content.DesiredSize.Width;
        SelectedIndex = _selected;
    }
}

代码隐藏:

public partial class MainWindow : Window
{
    public ObservableCollection<string> items { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        items = new ObservableCollection<string>();
        items.Add("test1");
        items.Add("test211111111111111");
        this.DataContext = this;
    }
}

和XAML:

<Window x:Class="ComboItems.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ComboItems"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:CustomComboBox x:Name="myCB" ItemsSource="{Binding items}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

编辑1

我刚刚用enum尝试过它:

<Window x:Class="ComboItems.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ComboItems"
    xmlns:windows="clr-namespace:System.Windows;assembly=PresentationCore"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="visibilityValues" 
                            ObjectType="{x:Type system:Enum}"
                            MethodName="GetValues">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="windows:Visibility" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Grid.Resources>
    <local:CustomComboBox x:Name="myCB"
                          FontSize="30" 
                          ItemsSource="{Binding Source={StaticResource visibilityValues}}" 
                          HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

字体也会改变,结果如下:

enter image description here

对我来说很好看。