Любой способ сохранить UIElement, созданный программно, в файле изображения?

Я пытаюсь сохранить UIElement, созданный программно в изображении JPG/PNG/BMP в приложении Windows Phone 8.1 (C#).

Я использую класс RenderTargetBitmap с помощью метода RenderAsync(), но он работает только с элементами пользовательского интерфейса, созданными в коде XAML. Когда я использую его для элементов пользовательского интерфейса, созданных непосредственно на C#, у меня возникает это исключение: «System.ArgumentException (значение не попадает в ожидаемый диапазон)».

Я делаю что-то не так или этот класс не позволяет отображать UIElement (ы), созданные программно? Есть ли способ сделать это на Windows Phone 8.1? Благодарю вас!

Вот код, который я использую:

        private static async void RenderText(string text, int width, int height, int fontsize, string imagename)
    {
        RenderTargetBitmap b = new RenderTargetBitmap();

        var canvas = new Grid();

        canvas.Width = width;
        canvas.Height = height;

        var background = new Canvas();
        background.Height = width;
        background.Width = height;

        SolidColorBrush backColor = new SolidColorBrush(Colors.Red);
        background.Background = backColor;

        var textBlock = new TextBlock();
        textBlock.Text = text;
        textBlock.FontWeight = FontWeights.Bold;
        textBlock.TextAlignment = TextAlignment.Left;
        textBlock.HorizontalAlignment = HorizontalAlignment.Center;
        textBlock.VerticalAlignment = VerticalAlignment.Stretch;
        textBlock.Margin = new Thickness(35);
        //textBlock.Width = b.PixelWidth - textBlock.Margin.Left * 2;
        textBlock.TextWrapping = TextWrapping.Wrap;
        textBlock.Foreground = new SolidColorBrush(Colors.White); //color of the text on the Tile
        textBlock.FontSize = fontsize;

        canvas.Children.Add(textBlock);

        await b.RenderAsync(background);
        await b.RenderAsync(canvas);

        // Get the pixels

        var pixelBuffer = await b.GetPixelsAsync();


        // Get the local folder.
        StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;

        // Create a new folder name DataFolder.
        var dataFolder = await local.CreateFolderAsync("DataFolder",
            CreationCollisionOption.OpenIfExists);

        StorageFile file = await dataFolder.CreateFileAsync(imagename, CreationCollisionOption.ReplaceExisting);


        // Encode the image to the selected file on disk
        using (var fileStream = await file.OpenStreamForWriteAsync())
        {

            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream.AsRandomAccessStream());

            encoder.SetPixelData(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Ignore,
                (uint)b.PixelWidth,
                (uint)b.PixelHeight,
                DisplayInformation.GetForCurrentView().LogicalDpi,
                DisplayInformation.GetForCurrentView().LogicalDpi,
                pixelBuffer.ToArray());

            await encoder.FlushAsync();
        }
    }

person DarioDP    schedule 06.04.2014    source источник


Ответы (2)


Он работает не только с элементами, созданными в XAML, но и с теми, которые (как MSDN говорит) находятся в VisualTree:

Визуализирует снимок UIElement визуального дерева в источник изображения.

Таким образом, ваш метод будет работать, если вы добавите свои элементы, например, на текущую страницу:

LayoutRoot.Children.Add(canvas);
person Romasz    schedule 09.04.2014

Ваши значения высоты и ширины UIEletet будут равны 0, когда вы создаете их с помощью кода. Если вы хотите, чтобы изображение имело определенное разрешение, попробуйте также присвоить UIElement ту же высоту и ширину. Код, показанный ниже, работал хорошо для меня.

    public static void SaveElementAsJPG(FrameworkElement element, string ImageName)
    {
        WriteableBitmap wBitmap = new WriteableBitmap(element, null);
        using (MemoryStream stream = new MemoryStream())
        {
            wBitmap.SaveJpeg(stream, (int)element.ActualWidth, (int)element.ActualHeight, 0, 100);
            wBitmap = null;
            //Use can either save the file to isolated storage or media library.
            //Creates file in Isolated Storage.
            using (var local = new IsolatedStorageFileStream(ImageName, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication()))
            {
                local.Write(stream.GetBuffer(), 0, stream.GetBuffer().Length);
            }
            //Creates file in Media Library.
            var lib = new MediaLibrary();
            var picture = lib.SavePicture(ImageName, stream.GetBuffer());
        }
    }
person Anzal M S    schedule 07.04.2014
comment
WriteableBitmap не имеет этого конструктора и метода SaveJpeg в Windows Phone 8.1, поэтому я использую RenderTargetBitmap... :\ - person DarioDP; 07.04.2014
comment
Кроме того, я установил ширину и высоту с помощью кода, я добавил фрагмент выше. - person DarioDP; 07.04.2014
comment
Даже если вы установите свойства Height и Width, ActualHeight и ActualWidth все равно будут равны нулю. Отсюда проблема. Я столкнулся с той же проблемой, и я поместил UIElement для экспорта на страницу. Затем нажмите кнопку экспорта, чтобы перейти на эту страницу, выполнить экспорт, а затем вернуться обратно. Требование моего клиента заключалось в том, чтобы экспортировать изображение и предложить поделиться им. Так что конечный пользователь никогда не увидит дополнительную страницу, которую мы создаем исключительно для экспорта изображения. - person Anzal M S; 07.04.2014