将XAML按钮渲染到PNG时的动态高度和宽度

时间:2009-08-04 02:43:54

标签: wpf xaml png

我正在整理原型以使用XAML创建PNG按钮。基本的想法是,可以从本地化的字符串生成漂亮的渐变图像按钮,而不是由任何类型的图形部门创建它们。

我发现的最直接的例子是构建一个C#程序集和call it from PHP。我将它转换为纯C#。这是我的基本工作原型的样子。

XAML文件如下所示:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Width="640" Height="480">

<Grid x:Name="LayoutRoot">
    <Button HorizontalAlignment="Left" VerticalAlignment="Top" Content="Add To Cart" FontFamily="Arial" FontSize="11" Height="24" FontWeight="Bold" Margin="0,3,0,0">
        <Button.Background>
            <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                <GradientStop Color="#FFF3F3F3" Offset="0"/>
                <GradientStop Color="#FFEBEBEB" Offset="0.5"/>
                <GradientStop Color="#FFDDDDDD" Offset="0.502"/>
                <GradientStop Color="#FFCDCDCD" Offset="1"/>
            </LinearGradientBrush>
        </Button.Background>
    </Button>
</Grid>

Program.cs看起来像:

class Program
{
    static void Main(string[] args)
    {
        FileInfo xamlFile = new FileInfo("Button.xaml");
        var inputXaml = File.ReadAllText(xamlFile.FullName);
        Thread pngCreationThread = new Thread((ThreadStart) delegate()
            {
                GenImageFromXaml(inputXaml);
            });
        pngCreationThread.IsBackground = true;
        pngCreationThread.SetApartmentState(ApartmentState.STA);
        pngCreationThread.Start();
        pngCreationThread.Join();
    }
    public static void GenImageFromXaml(string xaml)
    {
        var element = (FrameworkElement)XamlReader.Parse(xaml);
        var pngBytes = GetPngImage(element);

        using(BinaryWriter binWriter =
        new BinaryWriter(File.Open(@"output.png", FileMode.Create)))
        {
           binWriter.Write(pngBytes);
        }
    }
    private static byte[] GetPngImage(FrameworkElement element)
    {
        var size = new Size(element.Width, element.Height);
        element.Measure(size);
        element.Arrange(new Rect(size));
        var renderTarget =
          new RenderTargetBitmap((int)element.RenderSize.Width,
                                 (int)element.RenderSize.Height,
                                 96, 96,
                                 PixelFormats.Pbgra32);
        var sourceBrush = new VisualBrush(element);
        var drawingVisual = new DrawingVisual();
        using (DrawingContext drawingContext = drawingVisual.RenderOpen())
        {
            drawingContext.DrawRectangle(
                sourceBrush, null, new Rect(
                                       new Point(0, 0),
                                       new Point(element.RenderSize.Width,
                                       element.RenderSize.Height)));
        }
        renderTarget.Render(drawingVisual);
        var pngEncoder = new PngBitmapEncoder();
        pngEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
        using (var outputStream = new MemoryStream())
        {
            pngEncoder.Save(outputStream);
            return outputStream.ToArray();
        }
    }
}

我想要的是可以用作模板的XAML文件,并且交换按钮中的实际字符串。我的原型在基本级别上工作,从输入的XAML文件中渲染出一个图像。

但是,XAML文件明确指定高度和宽度。由于宽度不会事先知道而且任何字体修改都会混淆,因此按钮本身的字符串动态提供是一个问题。

我正在寻找的是一种在运行时计算高度和宽度的方法,或者根据文本字符串预先计算它们的简单方法。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您可以尝试下面的

1不要在xaml中设置宽度和高度

2替换您测量/安排来电:

var size = new Size(double.PositiveInfinity , double.PositiveInfinity );
element.Measure(size);
element.Arrange(new Rect(element.DesiredSize));

Measure根据您传递的大小设置DesiredSize属性,这可能是您希望它的大小。

3(不确定是否需要)将Grid(LayoutRoot)设置为Top / Left对齐,因为Grid希望默认采用所有可用的大小,你不希望这样。