【问题标题】:WPF stretched UserControl width doesn't match the width of its child horizontal StackPanelWPF 拉伸的 UserControl 宽度与其子水平 StackPanel 的宽度不匹配
【发布时间】:2011-10-18 09:07:58
【问题描述】:

第一次给我发帖:)

我的 UserControl 的宽度有这个问题,我似乎无法弄清楚。

基本上我有一个包含 ItemsControl 的 UserControl(panle 是一个水平 StackPanel)。该项目的 DataTemplate 是一个标准按钮。 我将一个字符串列表绑定到 ItemsControl,每个字符串都绑定到 Button 的 Content 属性。到现在都可以正常使用。

我需要做的是跟踪 ItemsControl 中每个单个项目(内部带有字符串的按钮)的宽度,即使它们没有被渲染。我需要这样做以动态(在调整大小时)删除超出 UserControl 最大宽度的项目,并在有足够空间时再次添加它们。

为了实现这一点,我使用以下函数测量每个字符串的宽度:

    private double GetTextWidth(string text)
    {
        FormattedText ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch), this.FontSize, this.Foreground);
        ft.Trimming = TextTrimming.CharacterEllipsis;
        return ft.WidthIncludingTrailingWhitespace;
    }

然后我手动给返回的值加上一个 6 的边距,这个边距就是 Button 需要的间距。 从我的列表中的字符串中汇总所有生成的值,我应该得到与我的 UserControl 几乎相同的宽度。由于所有布局都被拉伸(即使是 Window 中的 UserControl 也是如此),因此没有边距或填充(据我所知),并且只有一个宽度为 1 的边框。

问题是这不起作用,它需要我手动将一个相当大的值(45-65 个单位)添加到计算出的宽度上,以使其“像素完美”地工作。

我显然试图找到这个问题的根源,但无法。 首先我认为它是由 DIP 像素问题引起的,但事实并非如此。 我测量了单个字符串的宽度,然后测量了包含相同字符串的按钮的宽度。在所有情况下,第一个和第二个相差 6 个单位。 按钮之间没有可见的空间,所以我真的无法解释这么多开销的来源。 我唯一注意到的是,如果我更改 FontSize,我需要添加更改的值,但这很明显......

可能我错过了一些重要的东西,有什么想法吗? 感谢阅读!

【问题讨论】:

    标签: wpf user-controls measurement


    【解决方案1】:

    如果我理解正确,您想隐藏屏幕上不完全可见的项目。

    我过去曾使用辅助方法完成此操作,该方法将告诉我控件是否完全可见,如果控件不完全可见,则将控件的可见性设置为Hidden。我在LoadedSizeChanged 事件中实现了它。

    这是返回渲染控件可见性的帮助类:

    public enum ControlVisibility
    {
        Hidden,
        Partial,
        Full,
        FullHeightPartialWidth,
        FullWidthPartialHeight
    }
    
    
    /// <summary>
    /// Checks to see if an object is rendered visible within a parent container
    /// </summary>
    /// <param name="child">UI element of child object</param>
    /// <param name="parent">UI Element of parent object</param>
    /// <returns>ControlVisibility Enum</returns>
    public static ControlVisibility IsObjectVisibleInContainer(
        FrameworkElement child, UIElement parent)
    {
        GeneralTransform childTransform = child.TransformToAncestor(parent);
        Rect childSize = childTransform.TransformBounds(
            new Rect(new Point(0, 0), new Point(child.Width, child.Height)));
    
        Rect result = Rect.Intersect(
            new Rect(new Point(0, 0), parent.RenderSize), childSize);
    
        if (result == Rect.Empty)
        {
            return ControlVisibility.Hidden;
        }
        if (result.Height == childSize.Height && result.Width == childSize.Width)
        {
            return ControlVisibility.Full;
        }
        if (result.Height == childSize.Height)
        {
            return ControlVisibility.FullHeightPartialWidth;
        }
        if (result.Width == childSize.Width)
        {
            return ControlVisibility.FullWidthPartialHeight;
        }
        return ControlVisibility.Partial;
    }
    

    LoadedSizeChanged 事件背后的代码如下所示:

    ControlVisibility ctrlVisibility= 
        WPFHelpers.IsObjectVisibleInContainer(button, parent);
    
    if (ctrlVisibility == ControlVisibility.Full 
        || isVisible == ControlVisibility.FullWidthPartialHeight)
    {
        button.Visibility = Visibility.Visible;
    }
    else
    {
        button.Visibility = Visibility.Hidden;
    }
    

    【讨论】:

    • 谢谢 Rachel,你的代码看起来很有趣。问题是我无法直接访问子项(因为它们是模板化的),因此对 ItemsControl 的任何访问都只会返回给定的字符串对象,而不是我需要确定其呈现大小的 Button。
    • 我会把它放在TemplateButtonLoaded/SizeChanged 事件后面。要获取父级,您应该能够按名称引用 ItemsControl。如果它不起作用,您可以使用以下链接中的帮助程序类向上导航 Visual Tree 并找到包含按钮的 StackPanelrachel53461.wordpress.com/2011/10/09/…
    • 工作就像一个魅力,即使我没有完全按照你描述的方式,你的回答对我帮助很大。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 2018-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    相关资源
    最近更新 更多