具有测量/期望大小问题的Silverlight控件与来自中间用户控件的图像拉伸

时间:2011-05-22 13:23:34

标签: c# silverlight xaml layout custom-controls

我有一个自定义控件我正在处理并让它自己正常工作,但是当它是设置宽度的网格时我会遇到错误,例如:

元素'Microsoft.Windows.Design.Platform.SilverlightViewProducer + SilverlightContentHost'的布局测量覆盖不应将PositiveInfinity作为DesiredSize返回,即使Infinity以可用大小传入。

这些错误只发生在我的应用程序中而不是我的测试工具中 - 但是我不能在这里发布前者,但是我可能会在这里找到一些东西 - 可能能够弥补这个问题 - 但是如果有人可以的话帮助它会很棒

这是类代码:

public class UXImage : Control
    {
        #region Private Constants
        private const string RightImageControl = "RightImage";
        private const string MiddleImageControl = "MiddleImage";
        private const string LeftImageControl = "LeftImage";
        #endregion

    #region Private Members
    private int sourceHeight;
    private int sourceWidth;
    private int middleWidth = 1;
    WriteableBitmap crop;
    TransformGroup transform = new TransformGroup();
    TranslateTransform position = new TranslateTransform();
    ScaleTransform scale = new ScaleTransform();
    // Controls
    private Image image = new Image();
    private Image rightImageControl;
    private Image middleImageControl;
    private Image leftImageControl;
    #endregion

    #region Dependency Properties

    public static readonly DependencyProperty SourceProperty =
    DependencyProperty.Register("Source", typeof(BitmapSource),
    typeof(UXImage), null);

    public static readonly DependencyProperty RightCapWidthProperty =
    DependencyProperty.Register("RightCapWidth", typeof(int),
    typeof(UXImage), null);

    #endregion

    #region Public Properties

    public BitmapSource Source
    {
        get { return (BitmapSource)GetValue(SourceProperty); }
        set
        {
            SetValue(SourceProperty, value);
        }
    }

    public int RightCapWidth
    {
        get { return (int)GetValue(RightCapWidthProperty); }
        set
        {
            SetValue(RightCapWidthProperty, value);
        }
    }
    #endregion

    #region Public Methods

    /// <summary>
    /// On Apply Template
    /// </summary>
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        sourceHeight = Source.PixelHeight;
        sourceWidth = Source.PixelWidth;
        image.Source = Source;
        // Right Element
        rightImageControl = (Image)GetTemplateChild(RightImageControl);
        crop = new WriteableBitmap(RightCapWidth, sourceHeight);
        position.X = -sourceWidth + RightCapWidth;
        crop.Render(image, position);
        crop.Invalidate();
        rightImageControl.Source = crop;
        rightImageControl.Width = RightCapWidth;
        // Middle Element
        middleImageControl = (Image)GetTemplateChild(MiddleImageControl);
        crop = new WriteableBitmap(middleWidth, sourceHeight);
        position.X = -sourceWidth + RightCapWidth + middleWidth;
        crop.Render(image, position);
        crop.Invalidate();
        middleImageControl.Source = crop;
        middleImageControl.Height = sourceHeight;
        // Left Element
        leftImageControl = (Image)GetTemplateChild(LeftImageControl);
        crop = new WriteableBitmap(sourceWidth - RightCapWidth - middleWidth, sourceHeight);
        position.X = 0;
        crop.Render(image, position);
        crop.Invalidate();
        leftImageControl.Source = crop;
        leftImageControl.Height = sourceHeight;
        this.Height = sourceHeight;
        this.Width = sourceWidth;
    }

    public UXImage()
    {
        DefaultStyleKey = typeof(UXImage);
    }
    #endregion

}

Generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:local="clr-namespace:UXLibrary">
<Style TargetType="local:UXImage">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:UXImage">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Image x:Name="LeftImage" Stretch="Uniform" Source="{TemplateBinding Source}" Grid.Column="0"/>
                        <Image x:Name="MiddleImage" Stretch="Fill" Grid.Column="1"/>
                        <Image x:Name="RightImage" Stretch="Uniform" Grid.Column="2"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</ResourceDictionary>

用法:

<ux:UXImage RightCapWidth="10" Source="Images/example.png"/>

我在Silverlight中没有看到像这样的控件,是基于iOS和Android 9-Patch的UIImage,我听说过但没见过。 有人可以帮忙吗?如果这是一个解决方案,有没有其他方法可以做我正在做的事情,作为一个可以在中间伸展的图像元素。

1 个答案:

答案 0 :(得分:1)

我可以基本了解正在发生的事情以及如何继续进行的一些建议。通常,Control.WidthControl.Height属性适用于用户,而不是您。 控件应该将这些值作为输入,并将其用作布局过程的一部分,以影响生成的ActualWidthActualHeight属性。

现在,即使您从未打算让用户在XAML中指定WidthHeight,问题仍然是相同的。作为控件作者,您应该在MeasureOverrideArrangeOverride方法调用期间告诉布局系统您所需的大小:

特别是,由于您没有覆盖MeasureOverride,因此默认行为是返回第一个可视子项的所需大小,在您的情况下将是Grid,其大小未指定,因此希望尽可能大,即无限。

所以,解决方案听起来很简单:用MeasureOverrideArrangeOverride代替OnApplyTemplate计算尺寸,对吗?问题是,您可能无法在合适的时间获得所需的所有信息。如果你不这样做,那么你需要简单地返回你想要的大小的最佳猜测,然后当你得到正确的信息时,强制一个新的布局通过,以便MeasureOverride被调用再次。上面的链接和文档一般描述了如何执行此操作。