Эластичный WrapPanel и TextTrimming - PullRequest
       39

Эластичный WrapPanel и TextTrimming

0 голосов
/ 28 сентября 2011

Я пытаюсь создать Elastic WrapPanel. Это означает, что каждый столбец растягивается, чтобы соответствовать ширине панели, пока новый столбец не поместится внутри панели.

Ширина столбцов основана на ItemMinWidth.

Мне удалось создать панель, но моя проблема в том, что если я поставлю TextBlock и установлю TextTrimming в CharacterEllipsis. В моей панели это не будет работать. 3 точки не появятся. Похоже, ширина столбца работает, но контент, кажется, получает бесконечность как ширина.

Вот моя панель:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace WrapPanelTest
{
    public class ElasticWrapPanel : Panel
    {
        #region Constructor

        public ElasticWrapPanel()
        {
        }

        #endregion

        #region Properties

        [TypeConverter(typeof(LengthConverter))]
        public double ItemMinWidth
        {
            get
            {
                return (double)GetValue(ItemMinWidthProperty);
            }
            set
            {
                SetValue(ItemMinWidthProperty, value);
            }
        }

        public static readonly DependencyProperty ItemMinWidthProperty = DependencyProperty.Register("ItemMinWidth", typeof(double), typeof(ElasticWrapPanel));

        [TypeConverter(typeof(LengthConverter))]
        public double ColumnWidth
        {
            get
            {
                return (double)GetValue(ColumnWidthProperty);
            }
            private set
            {
                SetValue(ColumnWidthProperty, value);
            }
        }

        public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.Register("ColumnWidth", typeof(double), typeof(ElasticWrapPanel));

        #endregion

        #region Protected methods

        protected override Size MeasureOverride(Size availableSize)
        {
            _uiElementsRect.Clear();
            _columnCount = CalculateColumnCount(availableSize);

            if (_columnCount > 0)
            {
                ColumnWidth = (int)Math.Floor(availableSize.Width / _columnCount);
                double rowHeight = 0;
                double lastRowHeight = 0;
                int currentColumn = 0;
                int currentRow = 0;

                foreach (UIElement children in InternalChildren)
                {
                    children.Measure(availableSize);

                    rowHeight = Math.Max(rowHeight, children.DesiredSize.Height);

                    Rect childrenRect = new Rect(0, 0, 0, 0);
                    childrenRect.X = currentColumn * ColumnWidth;
                    childrenRect.Y = lastRowHeight;
                    childrenRect.Width = ColumnWidth;
                    childrenRect.Height = children.DesiredSize.Height;

                    _uiElementsRect.Add(children, childrenRect);

                    currentColumn++;

                    if (currentColumn == _columnCount)
                    {
                        lastRowHeight += rowHeight;
                        currentRow++;
                        rowHeight = 0;
                        currentColumn = 0;
                    }
                }
            }

            if (_uiElementsRect.Any())
            {
                double maxBottom = _uiElementsRect.Max(ui => ui.Value.Bottom);

                return new Size(availableSize.Width, maxBottom);
            }
            else
                return base.MeasureOverride(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (_columnCount > 0)
                foreach (KeyValuePair<UIElement, Rect> keyValuePair in _uiElementsRect)
                    keyValuePair.Key.Arrange(keyValuePair.Value);

            return base.ArrangeOverride(finalSize);
        }

        #endregion

        #region Private methods

        private int CalculateColumnCount(Size availableSize)
        {
            if (ItemMinWidth == 0 || Double.IsNaN(ItemMinWidth) || Double.IsInfinity(availableSize.Width))
                return 0;
            else
                return (int)Math.Floor(availableSize.Width / ItemMinWidth);
        }

        #endregion

        #region Private members

        int _columnCount = 0;

        IDictionary<UIElement, Rect> _uiElementsRect = new Dictionary<UIElement, Rect>();

        #endregion
    }
}

А вот пример по сравнению с WrapPanel, в которой работает TextTrimming:

<Window x:Class="WrapPanelTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WrapPanelTest"
        Title="MainWindow" 
        Height="480" 
        Width="640">

    <Window.Resources>

        <Style x:Key="TextBlockStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="Text" Value="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
            <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
            <Setter Property="Margin" Value="1"/>
            <Setter Property="Background" Value="Silver"/>
        </Style>

    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <WrapPanel ItemWidth="200">
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
        </WrapPanel>

        <local:ElasticWrapPanel ItemMinWidth="200" Grid.Row="1">
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
            <TextBlock Style="{StaticResource TextBlockStyle}"/>
        </local:ElasticWrapPanel>

    </Grid>
</Window>

Вы должны увидеть, что в WrapPanel 3 точки появляются в конце каждого элемента, но не на моей панели.

1 Ответ

2 голосов
/ 28 сентября 2011

Ваши текстовые блоки не имеют установленного размера, поэтому им разрешено растягиваться так, как им хотелось бы.

В качестве альтернативы рассмотрите возможность ограничения их размера в вашем MeasureOverride методе

foreach (UIElement children in InternalChildren)
{
    children.Measure(availableSize);

    ((FrameworkElement)children).MaxWidth = ColumnWidth;

    // Other code
}
...