Multipass MeasureOverride()会重新计算子大小

时间:2014-07-02 13:50:27

标签: wpf wpf-4.0

我有一个带有自定义控件的自定义面板,应该像 RibbonButton 一样调整大小,即因为可用的大小不同我应该删除/添加标题,调整内部图片等等...

此外,自定义控件是无形控件,即UI /模板在样式中定义,我使用触发器来更新模板元素。

通过使用继承的附加属性(我的意思是UI继承,如 DataContext ),我将大小设置从面板传递到各个控件

当我在面板中执行多次通过MeasureOverride()时,当我拨打child.Measure()时,就好像我的商品总是相同尺寸一样! 尽管我改变了继承的附加属性(它确实更新了内部控件!) 要明确我的内部控件不要调整大小,但是当我更改继承的属性时,他们会更改他们的UI模板(更小的版本)

我是否可以成功实现 RibbonButon RibbonGroupPanel 之类的行为?

1 个答案:

答案 0 :(得分:0)

我可能没有在我继承的属性上设置正确的元数据选项! 因为我设法让它调整它们的工作!

为了清楚起见,我将在下面发布我可以在下面写的最简单的样本(我以前没有做过,因为即使是最简单的样本也很长!!)

<强> Size123Control.cs

public class Size123Control : Control
{
    static Size123Control()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Size123Control), new FrameworkPropertyMetadata(typeof(Size123Control)));
    }
}

<强> Size123Panel.cs

public class Size123Panel : Panel
{
    public static int GetSize123(DependencyObject obj) { return (int)obj.GetValue(Size123Property); }

    public static void SetSize123(DependencyObject obj, int value) { obj.SetValue(Size123Property, value); }

    public static readonly DependencyProperty Size123Property = DependencyProperty.RegisterAttached(
        "Size123", typeof(int), typeof(Size123Panel), 
        new FrameworkPropertyMetadata(3,
            FrameworkPropertyMetadataOptions.Inherits
            | FrameworkPropertyMetadataOptions.AffectsMeasure
            | FrameworkPropertyMetadataOptions.AffectsParentMeasure
            | FrameworkPropertyMetadataOptions.AffectsArrange
            | FrameworkPropertyMetadataOptions.AffectsParentArrange
            ));

    protected override Size ArrangeOverride(Size finalSize)
    {
        double hTot = 0, h = 0, x = 0, xMax = 0;
        foreach (UIElement child in Children)
        {
            var cs = child.DesiredSize;
            if (x > 0 && x + cs.Width > finalSize.Width)
            {
                hTot += h;
                x = 0;
                h = cs.Height;
            }
            else
            {
                if (cs.Height > h)
                    h = cs.Height;
            }
            child.Arrange(new Rect(new Point(x, hTot), cs));
            x += cs.Width;
            if (x > xMax)
                xMax = x;
        }
        return new Size(xMax, hTot + h);
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        Func<Size> measure = () =>
        {
            double hTot = 0, h = 0, x = 0, xMax = 0;
            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
                var cs = child.DesiredSize;

                if (x > 0 && x + cs.Width > availableSize.Width)
                {
                    hTot += h;
                    x = 0;
                    h = cs.Height;
                }
                else
                {
                    if (cs.Height > h)
                        h = cs.Height;
                }
                x += cs.Width;
                if (x > xMax)
                    xMax = x;
            }
            return new Size(xMax, hTot + h);
        };

        SetSize123(this, 3);
        var s1 = measure();
        if (s1.Width <= availableSize.Width && s1.Height <= availableSize.Height)
            return s1;

        SetSize123(this, 2);
        var s2 = measure();
        if (s2.Width <= availableSize.Width && s2.Height <= availableSize.Height)
            return s2;

        SetSize123(this, 1);
        var s3 = measure();

        return s3;
    }
}

<强> generic.xaml

<Style TargetType="{x:Type local:Size123Control}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:Size123Control}">
                <Border x:Name="MAIN" Width="48" Height="48" Background="Red" BorderThickness="1" BorderBrush="LightGray"/>
                <ControlTemplate.Triggers>
                    <Trigger Property="local:Size123Panel.Size123" Value="2">
                        <Setter TargetName="MAIN" Property="Background" Value="Green"/>
                        <Setter TargetName="MAIN" Property="Width" Value="32"/>
                        <Setter TargetName="MAIN" Property="Height" Value="32"/>
                    </Trigger>
                    <Trigger Property="local:Size123Panel.Size123" Value="1">
                        <Setter TargetName="MAIN" Property="Background" Value="Blue"/>
                        <Setter TargetName="MAIN" Property="Width" Value="16"/>
                        <Setter TargetName="MAIN" Property="Height" Value="16"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<强> main.xaml

<local:Size123Panel>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
    <local:Size123Control/>
</local:Size123Panel>