Wpf 最后填充的包装纸

Wpf 最后填充的包装纸,wpf,silverlight,Wpf,Silverlight,我在数据输入表单上有一组用户控件。为了最大限度地利用空间,这些用户控件被放置在垂直展开的包装中。我的表单工作得很好,但在视觉上看起来并不完美。我在移动设备上打字,所以不能发布图片,但让我描述一下 假设表单有3个用户控件人口统计(宽度800)、电话(宽度300)、地址(宽度600)。表单本身有1000像素宽 现在,当这些用户控件被布置好(按照上面列出的顺序)时,人口统计信息将显示在第一行,其他两个用户控件将显示在下一行 但是人口统计控件将只显示行中可用1000像素中的800像素。同样地,最下面的一

我在数据输入表单上有一组用户控件。为了最大限度地利用空间,这些用户控件被放置在垂直展开的包装中。我的表单工作得很好,但在视觉上看起来并不完美。我在移动设备上打字,所以不能发布图片,但让我描述一下

假设表单有3个用户控件人口统计(宽度800)、电话(宽度300)、地址(宽度600)。表单本身有1000像素宽

现在,当这些用户控件被布置好(按照上面列出的顺序)时,人口统计信息将显示在第一行,其他两个用户控件将显示在下一行

但是人口统计控件将只显示行中可用1000像素中的800像素。同样地,最下面的一行只占900像素。这使得表格看起来很难看

我需要的是让每行中的最后一个孩子拉伸其边界bix(即其边界)以占据剩余空间。所以在这种情况下,人口统计的边界将延伸到1000像素,地址的边界将延伸到700像素

usercontrol集合是动态的。用户可以动态创建新表单并更改元素及其顺序

如果屏幕大小更改,拉伸的元素将恢复为其原始宽度,“包裹”面板将重新排列元素,每行的最后一个子元素将再次填充剩余空间


希望我能正确地解释情况。谢谢你抽出时间

最终编写了自己的自定义面板。在MeasureOverride中,创建新行之前的jyst返回到上次处理的控件,并将其长度设置为control.length+(maximumSize-lineSize)


这似乎很有效

我已经对此进行了控制。我发表在:

用法:

<wrapPanelWithFill:WrapPanelFill Grid.Row="3" Grid.Column="1">
        <TextBlock Text="Path: " TextWrapping="Wrap"></TextBlock>
        <TextBox MinWidth="120"  wrapPanelWithFill:WrapPanelFill.UseToFill="True">*</TextBox>
        <Button>Browse...</Button>
</wrapPanelWithFill:WrapPanelFill>

*
浏览。。。
代码:

使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Windows;
使用System.Windows.Controls;
命名空间WrapPanelWithFill
{
公共类WrapPanelFill:WrapPanel
{
// ******************************************************************
公共静态只读DependencyProperty UseToFillProperty=DependencyProperty.RegisterAttached(“UseToFill”,typeof(布尔),
typeof(WrapPanelFill),新的FrameworkPropertyMetadata(false,FrameworkPropertyMetadataOptions.AffectsRender));
// ******************************************************************
公共静态void SetUseToFill(UIElement元素,布尔值)
{
元素.SetValue(UseToFillProperty,value);
}
// ******************************************************************
公共静态布尔GetUseToFill(UIElement)
{
返回(布尔)元素.GetValue(UseToFillProperty);
}
// ******************************************************************
常数double DBL_EPSILON=2.2204460492503131e-016;/*最小值为1.0+DBL_EPSILON!=1.0*/
// ******************************************************************
专用静态布尔值DoubleAreClose(双值1,双值2)
{
//如果它们是无穷大(那么ε检查不起作用)
如果(value1==value2)返回true;
//这将计算(| value1-value2 |/(| value1 |+| value2 |+10.0))delta);
}
// ******************************************************************
专用静态布尔值加倍大于(双值1,双值2)
{
返回(value1>value2)和&!DoubleAreClose(value1,value2);
}
// ******************************************************************
private bool_atleastoneelement可以扩展其宽度=false;
// ******************************************************************
///  
/// 
///  
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
UVSize curLineSize=新的UVSize(方向);
UVSize panelSize=新的UVSize(方向);
UVSize uvConstraint=新的UVSize(方向、约束.宽度、约束.高度);
double itemWidth=itemWidth;
双项目高度=项目高度;
bool itemWidthSet=!Double.IsNaN(itemWidth);
bool itemHeightSet=!Double.IsNaN(itemHeight);
大小约束=新大小(
(itemWidthSet?itemWidth:constraint.Width),
(itemHeightSet?itemHeight:constraint.Height));
UIElementCollection子项=内部子项;
//环氧乙烷
LineInfo currentLineInfo=newlineinfo();//EO,它的工作方式总是像我们在当前线路上一样
_lineInfos.Clear();
_AtleastOneElementCanhasWidthExpanded=false;
for(int i=0,count=children.count;iusing System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;

namespace WrapPanelWithFill
{
    public class WrapPanelFill : WrapPanel
    {
        // ******************************************************************
        public static readonly DependencyProperty UseToFillProperty = DependencyProperty.RegisterAttached("UseToFill", typeof(Boolean), 
            typeof(WrapPanelFill), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));

        // ******************************************************************
        public static void SetUseToFill(UIElement element, Boolean value)
        {
            element.SetValue(UseToFillProperty, value);
        }
        // ******************************************************************
        public static Boolean GetUseToFill(UIElement element)
        {
            return (Boolean)element.GetValue(UseToFillProperty);
        }

        // ******************************************************************
        const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */

        // ******************************************************************
        private static bool DoubleAreClose(double value1, double value2)
        {
            //in case they are Infinities (then epsilon check does not work)
            if (value1 == value2) return true;
            // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
            double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
            double delta = value1 - value2;
            return (-eps < delta) && (eps > delta);
        }

        // ******************************************************************
        private static bool DoubleGreaterThan(double value1, double value2)
        {
            return (value1 > value2) && !DoubleAreClose(value1, value2);
        }

        // ******************************************************************
        private bool _atLeastOneElementCanHasItsWidthExpanded = false;

        // ******************************************************************
        /// <summary> 
        /// <see cref="FrameworkElement.MeasureOverride"/>
        /// </summary> 
        protected override Size MeasureOverride(Size constraint)
        {
            UVSize curLineSize = new UVSize(Orientation);
            UVSize panelSize = new UVSize(Orientation);
            UVSize uvConstraint = new UVSize(Orientation, constraint.Width, constraint.Height);
            double itemWidth = ItemWidth;
            double itemHeight = ItemHeight;
            bool itemWidthSet = !Double.IsNaN(itemWidth);
            bool itemHeightSet = !Double.IsNaN(itemHeight);

            Size childConstraint = new Size(
                (itemWidthSet ? itemWidth : constraint.Width),
                (itemHeightSet ? itemHeight : constraint.Height));

            UIElementCollection children = InternalChildren;

            // EO
            LineInfo currentLineInfo = new LineInfo(); // EO, the way it works it is always like we are on the current line
            _lineInfos.Clear();
            _atLeastOneElementCanHasItsWidthExpanded = false;

            for (int i = 0, count = children.Count; i < count; i++)
            {
                UIElement child = children[i] as UIElement;
                if (child == null) continue;

                //Flow passes its own constrint to children 
                child.Measure(childConstraint);

                //this is the size of the child in UV space 
                UVSize sz = new UVSize(
                    Orientation,
                    (itemWidthSet ? itemWidth : child.DesiredSize.Width),
                    (itemHeightSet ? itemHeight : child.DesiredSize.Height));

                if (DoubleGreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line 
                {
                    // EO
                    currentLineInfo.Size = curLineSize;
                    _lineInfos.Add(currentLineInfo);

                    panelSize.U = Math.Max(curLineSize.U, panelSize.U);
                    panelSize.V += curLineSize.V;
                    curLineSize = sz;

                    // EO
                    currentLineInfo = new LineInfo();
                    var feChild = child as FrameworkElement;
                    if (GetUseToFill(feChild))
                    {
                        currentLineInfo.ElementsWithNoWidthSet.Add(feChild);
                        _atLeastOneElementCanHasItsWidthExpanded = true;
                    }

                    if (DoubleGreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line
                    {
                        currentLineInfo = new LineInfo();

                        panelSize.U = Math.Max(sz.U, panelSize.U);
                        panelSize.V += sz.V;
                        curLineSize = new UVSize(Orientation);
                    }
                }
                else //continue to accumulate a line
                {
                    curLineSize.U += sz.U;
                    curLineSize.V = Math.Max(sz.V, curLineSize.V);

                    // EO
                    var feChild = child as FrameworkElement;
                    if (GetUseToFill(feChild))
                    {
                        currentLineInfo.ElementsWithNoWidthSet.Add(feChild);
                        _atLeastOneElementCanHasItsWidthExpanded = true;
                    }
                }
            }

            if (curLineSize.U > 0)
            {
                currentLineInfo.Size = curLineSize;
                _lineInfos.Add(currentLineInfo);
            }

            //the last line size, if any should be added 
            panelSize.U = Math.Max(curLineSize.U, panelSize.U);
            panelSize.V += curLineSize.V;

            // EO
            if (_atLeastOneElementCanHasItsWidthExpanded)
            {
                return new Size(constraint.Width, panelSize.Height);
            }

            //go from UV space to W/H space
            return new Size(panelSize.Width, panelSize.Height);
        }

        // ************************************************************************
        private struct UVSize
        {
            internal UVSize(Orientation orientation, double width, double height)
            {
                U = V = 0d;
                _orientation = orientation;
                Width = width;
                Height = height;
            }

            internal UVSize(Orientation orientation)
            {
                U = V = 0d;
                _orientation = orientation;
            }

            internal double U;
            internal double V;
            private Orientation _orientation;

            internal double Width
            {
                get { return (_orientation == Orientation.Horizontal ? U : V); }
                set { if (_orientation == Orientation.Horizontal) U = value; else V = value; }
            }
            internal double Height
            {
                get { return (_orientation == Orientation.Horizontal ? V : U); }
                set { if (_orientation == Orientation.Horizontal) V = value; else U = value; }
            }
        }

        // ************************************************************************
        private class LineInfo
        {
            public List<UIElement> ElementsWithNoWidthSet = new List<UIElement>();
            //          public double SpaceLeft = 0;
            //          public double WidthCorrectionPerElement = 0;
            public UVSize Size;
            public double Correction = 0;
        }

        private List<LineInfo> _lineInfos = new List<LineInfo>();

        // ************************************************************************
        /// <summary>
        /// <see cref="FrameworkElement.ArrangeOverride"/> 
        /// </summary> 
        protected override Size ArrangeOverride(Size finalSize)
        {
            int lineIndex = 0;
            int firstInLine = 0;
            double itemWidth = ItemWidth;
            double itemHeight = ItemHeight;
            double accumulatedV = 0;
            double itemU = (Orientation == Orientation.Horizontal ? itemWidth : itemHeight);
            UVSize curLineSize = new UVSize(Orientation);
            UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height);
            bool itemWidthSet = !Double.IsNaN(itemWidth);
            bool itemHeightSet = !Double.IsNaN(itemHeight);
            bool useItemU = (Orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet);

            UIElementCollection children = InternalChildren;

            for (int i = 0, count = children.Count; i < count; i++)
            {
                UIElement child = children[i] as UIElement;
                if (child == null) continue;

                UVSize sz = new UVSize(
                    Orientation,
                    (itemWidthSet ? itemWidth : child.DesiredSize.Width),
                    (itemHeightSet ? itemHeight : child.DesiredSize.Height));

                if (DoubleGreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line 
                {
                    arrangeLine(lineIndex, accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU, uvFinalSize);
                    lineIndex++;

                    accumulatedV += curLineSize.V;
                    curLineSize = sz;

                    if (DoubleGreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line 
                    {
                        //switch to next line which only contain one element 
                        arrangeLine(lineIndex, accumulatedV, sz.V, i, ++i, useItemU, itemU, uvFinalSize);

                        accumulatedV += sz.V;
                        curLineSize = new UVSize(Orientation);
                    }
                    firstInLine = i;
                }
                else //continue to accumulate a line
                {
                    curLineSize.U += sz.U;
                    curLineSize.V = Math.Max(sz.V, curLineSize.V);
                }
            }

            //arrange the last line, if any
            if (firstInLine < children.Count)
            {
                arrangeLine(lineIndex, accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU, uvFinalSize);
            }

            return finalSize;
        }

        // ************************************************************************
        private void arrangeLine(int lineIndex, double v, double lineV, int start, int end, bool useItemU, double itemU, UVSize uvFinalSize)
        {
            double u = 0;
            bool isHorizontal = (Orientation == Orientation.Horizontal);

            Debug.Assert(lineIndex < _lineInfos.Count);

            LineInfo lineInfo = _lineInfos[lineIndex];
            double lineSpaceAvailableForCorrection = Math.Max(uvFinalSize.U - lineInfo.Size.U, 0);
            double perControlCorrection = 0;
            if (lineSpaceAvailableForCorrection > 0 && lineInfo.Size.U > 0)
            {
                perControlCorrection = lineSpaceAvailableForCorrection / lineInfo.ElementsWithNoWidthSet.Count;
                if (double.IsInfinity(perControlCorrection))
                {
                    perControlCorrection = 0;
                }
            }
            int indexOfControlToAdjustSizeToFill = 0;
            UIElement uIElementToAdjustNext = indexOfControlToAdjustSizeToFill < lineInfo.ElementsWithNoWidthSet.Count ? lineInfo.ElementsWithNoWidthSet[indexOfControlToAdjustSizeToFill] : null;

            UIElementCollection children = InternalChildren;
            for (int i = start; i < end; i++)
            {
                UIElement child = children[i] as UIElement;
                if (child != null)
                {
                    UVSize childSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
                    double layoutSlotU = (useItemU ? itemU : childSize.U);

                    if (perControlCorrection > 0 && child == uIElementToAdjustNext)
                    {
                        layoutSlotU += perControlCorrection;

                        indexOfControlToAdjustSizeToFill++;
                        uIElementToAdjustNext = indexOfControlToAdjustSizeToFill < lineInfo.ElementsWithNoWidthSet.Count ? lineInfo.ElementsWithNoWidthSet[indexOfControlToAdjustSizeToFill] : null;
                    }

                    child.Arrange(new Rect(
                        (isHorizontal ? u : v),
                        (isHorizontal ? v : u),
                        (isHorizontal ? layoutSlotU : lineV),
                        (isHorizontal ? lineV : layoutSlotU)));
                    u += layoutSlotU;
                }
            }
        }

        // ************************************************************************

    }
}