Растянутая ширина пользовательского элемента управления WPF не соответствует ширине его дочернего горизонтального элемента StackPanel - PullRequest
0 голосов
/ 18 октября 2011

первый пост для меня:)

У меня проблема с шириной моего UserControl, которую я просто не могу понять.

По сути, у меня есть UserControl, который содержит ItemsControl (panle - горизонтальная панель стека). DataTemplate элемента является стандартной кнопкой. Я связываю список строк с ItemsControl, и каждая строка связывается со свойством 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 к возвращаемому значению, это поле - необходимый интервал для кнопки. Суммируя все сгенерированные значения из строк в моем списке, я должен получить почти ту же ширину, что и мой UserControl. Поскольку все макеты растянуты (даже пользовательский элемент управления в окне), маржа или отступы не выполняются (насколько я вижу), и есть только одна граница с шириной 1.

Проблема в том, что это не работает, мне нужно вручную добавить довольно большое значение (45-65 единиц) к вычисленной ширине, чтобы заставить его работать "безупречно".

Я явно пытался найти корень этой проблемы, но не смог. Сначала я подумал, что это вызвано проблемой DIP <-> Pixel, но это не так. Я измерил ширину одной строки, а затем ширину кнопки, содержащей ту же строку. Во всех сценариях первое и второе отличаются на 6 единиц. Между кнопками нет видимого пространства, поэтому я действительно не могу объяснить, откуда взялись такие большие накладные расходы. Единственное, что я заметил, это то, что значение, которое мне нужно добавить, меняется, если я изменяю FontSize, но это довольно очевидно ...

Возможно, мне не хватает чего-то большого, есть идеи? Спасибо за чтение!

1 Ответ

0 голосов
/ 18 октября 2011

Если я вас правильно понимаю, вы хотите скрыть элементы, которые не полностью видны на экране.

В прошлом я делал это с помощью вспомогательного метода, который сообщит мне, является ли элемент управления полностью видимым или нет, и установит видимость элемента управления на Hidden, если элемент управления не будет полностью виден. Я реализовал это в событиях Loaded и SizeChanged.

Вот вспомогательный класс, который возвратил видимость визуализированного элемента управления:

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;
}

Код позади событий Loaded и SizeChanged выглядел примерно так:

ControlVisibility ctrlVisibility= 
    WPFHelpers.IsObjectVisibleInContainer(button, parent);

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