WPF拉伸的UserControl宽度与其子级StackPanel的宽度不匹配

时间:2011-10-18 09:07:58

标签: wpf user-controls measurement

我第一次发帖:)

我的UserControl宽度出现了这个问题,我似乎无法弄明白。

基本上我有一个包含ItemsControl的UserControl(panle是一个水平StackPanel)。该项的DataTemplate是一个标准Button。 我将一个字符串List绑定到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所需的间距。 对我的List中的字符串中的所有生成值求和,我应该得到与UserControl几乎相同的宽度。由于所有布局都被拉伸(即使是窗口中的UserControl),也没有边距或填充(据我所见),并且只有一个宽度为1的边框。

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

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

可能我错过了一些重大的想法? 谢谢你的阅读!

1 个答案:

答案 0 :(得分:0)

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

我过去使用辅助方法完成此操作,该方法将告诉我控件是否完全可见,并且如果控件不完全可见,则将控件的可见性设置为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;
}