如何获取 ComboBox 模板中 Popup 的宽度

How to get width of Popup thats in the ComboBox template

我有这个 IMultiValueConverter,我想在它列出更改值时计算出 ComboBox 的宽度。

我查看了 MSDN ComboBox 模板,可以看到有一个 Popup,带有 x:Name="Popup",实际上在页面顶部他们称之为有点混乱PART_Popup。 MSDN link

如何获取 Popup 对象以确定其宽度?如果出于某种原因无法选择 Popup,那么其中的 Grid 又如何呢。

之前看到别人遍历所有项寻找文本渲染的最大长度,如果可能的话我想试试这个方法。

public class ComboBoxWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double cbxWidth = 100;

        if (values[0] == null || values[1] == null)
            return cbxWidth;

        ComboBox cb = (ComboBox)values[0];

        int itemCount = (int)values[1];

        if (itemCount == 0)
            return cbxWidth;

        //Find popup and retrieve width.

        return cbxWidth;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这行得通:您可能会想办法将它集成到您​​的 Converter 中。

  void MainWindow_Loaded(object sender, RoutedEventArgs e)
  {
       // comboBox is an element in 'MainWindow'
       var popup = VisualTreeHelperExtensions.FindVisualChild<Popup>(comboBox);
  }

  public static T FindVisualChild<T>(DependencyObject depObj) where T : Visual
    {
        if (depObj != null && IsVisual(depObj))
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

                if (child != null && child is T)
                {
                    return (T)child;
                }

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

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj == null)
            yield break;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            if (IsVisual(depObj))
            {
                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;
                }
            }
        }
    }

    private static bool IsVisual(DependencyObject depObj)
    {
        return depObj is Visual || depObj is Visual3D;
    }