Динамическая высота и ширина при рендеринге кнопок XAML в PNG - PullRequest
0 голосов
/ 04 августа 2009

Я собираю прототип для использования XAML для создания кнопок PNG. Основная идея заключается в том, что красивые градиентные кнопки изображения могут быть сгенерированы из локализованных строк вместо того, чтобы создавать их любым графическим отделом.

Самый простой пример, который я нашел, на самом деле заключался в том, чтобы собрать сборку C # и вызвать ее из 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 Ответ

2 голосов
/ 04 августа 2009

Вы можете попробовать следующее

1 Не задавайте ширину и высоту в xaml

2 Замените ваши измерения / упорядочите вызовы следующим образом:

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

Measure устанавливает свойство DesiredSize в зависимости от размера, который вы передаете, вероятно, это тот размер, который вам нужен.

3 (не уверен, если это необходимо). Установите для своей сетки (LayoutRoot) выравнивание по верхнему / левому краям, поскольку сетка по умолчанию предпочитает брать все доступные размеры, этого не требуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...