xaml(written by myself on the back end) and save to it as image , but the image is block

    // aaa.xaml.cs

     public void saveImageInAdmin()
            StackPanel sp = new StackPanel();
            sp.Width = 400;
            sp.Height = 400;
            sp.Background = Brushes.Blue;
            Button myButton = new Button();
            myButton.Content = "Press me";
            var bmp = new RenderTargetBitmap(400,  400, 96, 96, PixelFormats.Default);
            if (!Directory.Exists(@".\images"))
            using (Stream stm = File.Create(@$".\images\1.png"))
               BitmapEncoder encoder = new PngBitmapEncoder();

I want to manually generate the xmal control in the back end, and then use the function to convert it into a picture and save it, but I post the saved picture with nothing.the image's color is black, why?? please help me.


1 answer

  • answered 2020-06-27 09:19 Andy

    If this is a service with no wpf front end then that isn't intended to be supported. You can try setting ShouldRenderEvenWhenNoDisplayDevicesAreAvailable true. https://github.com/dotnet/wpf/issues/2811

    I see some other potential issues there as well.
    You can find sizing problems with controls grabbing margin from their parent.

    I also found that code which worked OK with .net "old" had problems with .net core.

    One of the apps I have in the General Staff suite is a map editor. You use it to edit the map you will use to play a battle on. Part of map editing captures a picture. This is of a set of UI which can be extremely complex.

    Here's my code:

        public async Task GeneratePng(Grid mapGrid, string pngURI)
            double dpi = App.mvm.SelectedDPI;
            Size size = new Size(Map.Width, Map.Height);
            double scale = dpi / 96;
            Rect rect = new Rect(0,0, Map.Width, Map.Height);
            mapGrid.ClipToBounds = true;
            await Task.Delay(100);
            RenderTargetBitmap rt = new RenderTargetBitmap((int)(Map.Width * scale),
                                                           (int)(Map.Height * scale),
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext ctx = dv.RenderOpen())
                VisualBrush vb = new VisualBrush(mapGrid);
                ctx.DrawRectangle(vb, null, rect);
            PngBitmapEncoder png = new PngBitmapEncoder();
            using (Stream streamPng = File.Create(pngURI))


    public static class Visuals
        public static void AllowUIToUpdate()
            DispatcherFrame frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate (object parameter)
                frame.Continue = false;
                return null;
            }), null);
                                          new Action(delegate { }));

    Note that some of the the fiddly bits like the delay I've got in there are probably not necessary for most purposes. A user can add very complicated UI to build a map and it can take a while to render.

    Taking code out is way easier than guessing at what unusual code you need to add.

    As an aside.

    Those complicated objects like the 15,000 individually rendered tree usercontrols aren't used in the game. The picture captured is used as a background and of course renders way faster.