Может ли WPF listbox обойти другой компонент? - PullRequest
0 голосов
/ 26 сентября 2019

Мне нужно зафиксировать справа в окне текстовый блок, в котором я установил Примечание, остальная часть окна может быть списком, заполненным выбираемыми элементами.Моя проблема в том, что заметка может быть видимой или нет, а выбираемые элементы должны быть обернуты вокруг, как в Word с изображением и текстом обтекания, установленным в «Квадрат»

Примеры:

Note with one selectable item Note with multiple selectable items

ДОБАВЛЕНО

Я создал пользовательский UniformGrid, добавил свойство NoteRowToSkip, которое представляет строки для пропускав последнем столбце слева.Я переопределил ArrangeOverride и добавил желаемое поведение пропуска.Отладка кажется, что значения правильные, но имеет то же поведение UniformGrid.

    public class UniformNoteWrapGrid : Panel
    {
        private int m_Rows;
        private int m_Columns;

        public static readonly DependencyProperty NoteRowToSkipProperty = DependencyProperty.Register(nameof(NoteRowToSkip), typeof(int), typeof(UniformGrid), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateNoteRowToSkip);
        private static bool ValidateNoteRowToSkip(object o)
        {
            return (int)o >= 0;
        }
        public int Columns
        {
            get => (int)GetValue(ColumnsProperty);
            set => SetValue(ColumnsProperty, value);
        }

        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register(
                "Columns",
                typeof(int),
                typeof(UniformGrid),
                new FrameworkPropertyMetadata(
                    0,
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                ValidateColumns);

        private static bool ValidateColumns(object o)
        {
            return (int)o >= 0;
        }

        public int Rows
        {
            get => (int)GetValue(RowsProperty);
            set => SetValue(RowsProperty, value);
        }

        public static readonly DependencyProperty RowsProperty =
            DependencyProperty.Register("Rows", typeof(int),
                typeof(UniformGrid),
                new FrameworkPropertyMetadata(
                    0,
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                ValidateRows);

        private static bool ValidateRows(object o)
        {
            return (int)o >= 0;
        }

        public int NoteRowToSkip
        {
            get => (int)GetValue(NoteRowToSkipProperty);
            set => SetValue(NoteRowToSkipProperty, value);
        }

        protected override Size MeasureOverride(Size constraint)
        {
            UpdateComputedValues();

            var childConstraint = new Size(constraint.Width / m_Columns, constraint.Height / m_Rows);
            double maxChildDesiredWidth = 0.0;
            double maxChildDesiredHeight = 0.0;

            for (int i = 0, count = InternalChildren.Count; i < count; ++i)
            {
                var child = InternalChildren[i];

                child.Measure(childConstraint);
                var childDesiredSize = child.DesiredSize;

                if (maxChildDesiredWidth < childDesiredSize.Width)
                    maxChildDesiredWidth = childDesiredSize.Width;

                if (maxChildDesiredHeight < childDesiredSize.Height)
                    maxChildDesiredHeight = childDesiredSize.Height;
            }

            return new Size(maxChildDesiredWidth * m_Columns, maxChildDesiredHeight * m_Rows);
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            var childBounds = new Rect(0, 0, arrangeSize.Width / m_Columns, arrangeSize.Height / m_Rows);
            double xStep = childBounds.Width;
            double xBound = arrangeSize.Width - 1.0;
            var row = 1;
            var column = 1;

            foreach (UIElement child in InternalChildren)
            {
                child.Arrange(childBounds);

                if (child.Visibility == Visibility.Collapsed)
                    continue;

                childBounds.X += xStep;
                column++;
                var testXBound = xBound;
                if (IsCellForNote(row, column))
                    testXBound -= childBounds.Height;

                if (!(childBounds.X >= testXBound))
                    continue;

                childBounds.Y += childBounds.Height;
                childBounds.X = 0;
                row++;
                column = 1;
            }

            return arrangeSize;
        }

        private bool IsCellForNote(int row, int column)
        {
            if (row > NoteRowToSkip)
                return true;

            return column != Columns;
        }

        private void UpdateComputedValues()
        {
            m_Columns = Columns;
            m_Rows = Rows;

            //if (FirstColumn >= m_Columns)
            //  FirstColumn = 0;

            if (m_Rows != 0 && m_Columns != 0)
                return;

            int nonCollapsedCount = 0;

            for (int i = 0, count = InternalChildren.Count; i < count; ++i)
            {
                var child = InternalChildren[i];
                if (child.Visibility != Visibility.Collapsed)
                    nonCollapsedCount++;
            }

            if (nonCollapsedCount == 0)
                nonCollapsedCount = 1;

            if (m_Rows == 0)
            {
                if (m_Columns > 0)
                    m_Rows = (nonCollapsedCount + (m_Columns - 1)) / m_Columns;
                else
                {
                    m_Rows = (int)Math.Sqrt(nonCollapsedCount);
                    if ((m_Rows * m_Rows) < nonCollapsedCount)
                        m_Rows++;

                    m_Columns = m_Rows;
                }
            }
            else if (m_Columns == 0)
                m_Columns = (nonCollapsedCount + (m_Rows - 1)) / m_Rows;
        }
    }

Есть идеи, что не работает в моем коде?

решено

Была проблема с условиями.Рабочая версия ниже.

    public class UniformNoteWrapGrid : Panel
    {
        private int m_Rows;
        private int m_Columns;

        public static readonly DependencyProperty NoteRowToSkipProperty = DependencyProperty.Register(nameof(NoteRowToSkip), typeof(int), typeof(UniformGrid), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateNoteRowToSkip);
        private static bool ValidateNoteRowToSkip(object o)
        {
            return (int)o >= 0;
        }

        public int Columns
        {
            get => (int)GetValue(ColumnsProperty);
            set => SetValue(ColumnsProperty, value);
        }

        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register(
                "Columns",
                typeof(int),
                typeof(UniformGrid),
                new FrameworkPropertyMetadata(
                    0,
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                ValidateColumns);

        private static bool ValidateColumns(object o)
        {
            return (int)o >= 0;
        }

        public int Rows
        {
            get => (int)GetValue(RowsProperty);
            set => SetValue(RowsProperty, value);
        }

        public static readonly DependencyProperty RowsProperty =
            DependencyProperty.Register("Rows", typeof(int),
                typeof(UniformGrid),
                new FrameworkPropertyMetadata(
                    0,
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                ValidateRows);

        private static bool ValidateRows(object o)
        {
            return (int)o >= 0;
        }

        public int NoteRowToSkip
        {
            get => (int)GetValue(NoteRowToSkipProperty);
            set => SetValue(NoteRowToSkipProperty, value);
        }

        protected override Size MeasureOverride(Size constraint)
        {
            UpdateComputedValues();

            var childConstraint = new Size(constraint.Width / m_Columns, constraint.Height / m_Rows);
            double maxChildDesiredWidth = 0.0;
            double maxChildDesiredHeight = 0.0;

            for (int i = 0, count = InternalChildren.Count; i < count; ++i)
            {
                var child = InternalChildren[i];

                child.Measure(childConstraint);
                var childDesiredSize = child.DesiredSize;

                if (maxChildDesiredWidth < childDesiredSize.Width)
                    maxChildDesiredWidth = childDesiredSize.Width;

                if (maxChildDesiredHeight < childDesiredSize.Height)
                    maxChildDesiredHeight = childDesiredSize.Height;
            }

            return new Size(maxChildDesiredWidth * m_Columns, maxChildDesiredHeight * m_Rows);
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            var childBounds = new Rect(0, 0, arrangeSize.Width / m_Columns, arrangeSize.Height / m_Rows);
            double xStep = childBounds.Width;
            double xBound = arrangeSize.Width - 1.0;
            var row = 1;
            var column = 1;

            foreach (UIElement child in InternalChildren)
            {
                child.Arrange(childBounds);

                if (child.Visibility == Visibility.Collapsed)
                    continue;

                childBounds.X += xStep;
                column++;
                var testXBound = xBound;
                if (IsCellForNote(row, column))
                    testXBound -= xStep;

                if (!(childBounds.X >= testXBound))
                    continue;

                childBounds.Y += childBounds.Height;
                childBounds.X = 0;
                row++;
                column = 1;
            }

            return arrangeSize;
        }

        private bool IsCellForNote(int row, int column)
        {
            if (row > NoteRowToSkip)
                return false;

            return column == Columns;
        }

        private void UpdateComputedValues()
        {
            m_Columns = Columns;
            m_Rows = Rows;

            //if (FirstColumn >= m_Columns)
            //  FirstColumn = 0;

            if (m_Rows != 0 && m_Columns != 0)
                return;

            int nonCollapsedCount = 0;

            for (int i = 0, count = InternalChildren.Count; i < count; ++i)
            {
                var child = InternalChildren[i];
                if (child.Visibility != Visibility.Collapsed)
                    nonCollapsedCount++;
            }

            if (nonCollapsedCount == 0)
                nonCollapsedCount = 1;

            if (m_Rows == 0)
            {
                if (m_Columns > 0)
                    m_Rows = (nonCollapsedCount + (m_Columns - 1)) / m_Columns;
                else
                {
                    m_Rows = (int)Math.Sqrt(nonCollapsedCount);
                    if ((m_Rows * m_Rows) < nonCollapsedCount)
                        m_Rows++;

                    m_Columns = m_Rows;
                }
            }
            else if (m_Columns == 0)
                m_Columns = (nonCollapsedCount + (m_Rows - 1)) / m_Rows;
        }
    }

1 Ответ

0 голосов
/ 26 сентября 2019

WrapPanel с небольшим количеством настроек может помочь вам достичь чего-то вроде этого:

enter image description here

Здесь я использовал ItemsControl в качестве хостадля элементов с WrapPanel как ItemsPanelTemplate:

<ItemsControl x:Name="panel">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type local:NoteItem}">
                <TextBlock HorizontalAlignment="Right" TextWrapping="Wrap" Width="50" Height="150" Margin="10" 
                           Text="{Binding Text}" Background="LightBlue">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Setter Property="Visibility" Value="Visible"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Visible}" Value="False" >
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:ListItem}">
                <TextBlock TextWrapping="Wrap" Width="50" Height="50" Margin="10" Text="{Binding Text}" Background="LightGray"/>
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

И чтобы попробовать это, поместите это в коде:

public class Item
{
    public string Text { get; set; }
}

public class NoteItem:Item
{
    public bool Visible{ get; set; }
}

public class ListItem : Item
{
}

public partial class MainWindow : Window
{

    ObservableCollection<Item> list = new ObservableCollection<Item>();

    public MainWindow()
    {
        InitializeComponent();

        NoteItem note = new NoteItem { Text = "This is a note", Visible = true };
        list.Add(note);
        for(int i=0;i<20; i++)
            list.Add(new ListItem { Text = "This is a list item" });
        panel.ItemsSource = list;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...