×

Discussion Board

Page 1 of 2 12 LastLast
Results 1 to 15 of 25
  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Export a screenshot of a component that's not visible

    Hi there.

    I don't know if mine is an usuale request or not, but I need your help to solve this thing.

    I've got a component which shows data taken from a data model.
    What I want to do is to save a screenshot of this component in the user's media library.

    The problem is that the component is not shown when I want to save it, but I'm creating it through code.

    To make things clearer, here's some code:

    Code:
    public static void SaveScreenshot(Model model)
    {
        var control = new MyControl(model);
        var bitmap = new WriteableBitmap(control.LayoutRoot, null); // HERE COMES THE EXCEPTION!
        using (var mediaGallery = new MediaLibrary())
        {
            using (var stream = new MemoryStream())
            {
                bitmap.SaveJpeg(stream, bitmap.PixelWidth, bitmap.PixelHeight, 0, 100);
                mediaGallery.SavePicture(FILE_NAME, stream);
            }
        }
        MessageBox.Show("Picture saved");
    }
    Here's the exception:
    First-chance exception 'System.Exception' in System.Windows.ni.dll
    Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
    Using the debugger, I can see that the component is built correctly, and all the data is inside (layout is loaded and DataContext is set to the right object).

    What I don't understand is why it throws the exception since everything looks fine.

    As you may need it, here's some code of MyControl:

    - XAML:
    Code:
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
        <ItemsControl ItemsSource="{Binding Items}"
                              x:Name="ItemsArea"
                              IsHitTestVisible="True">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="{StaticResource PhoneForegroundBrush}"
                                    Margin="{Binding WidgetPosition, Mode=TwoWay}"
                                    Width="{Binding WidgetWidth, Mode=TwoWay}"
                                    Height="{Binding WidgetHeight, Mode=TwoWay}"
                                    IsHitTestVisible="True">
                        <stuff:Stuff/>
                        <toolkit:GestureService.GestureListener>
                            <toolkit:GestureListener 
                                        DoubleTap="GestureListener_OnDoubleTap"
                                        Tap="GestureListener_OnTap"
                                        GestureBegin="GestureListener_OnGestureBegin"
                                        DragDelta="GestureListener_OnDragDelta"
                                        GestureCompleted="GestureListener_OnGestureCompleted" />
                        </toolkit:GestureService.GestureListener>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas x:Name="ItemsCanvas" 
                                    Background="{StaticResource PhoneBackgroundBrush}"
                                    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                    IsHitTestVisible="True"
                                    Canvas.ZIndex="2"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
    - C#
    Code:
    public partial class MyControl : UserControl
    {
    
        internal readonly Model Model;
    
        public MyControl()
        {
            InitializeComponent();
            // Get our datacontext            
            if (!NavigationHelper.TryGetParameter("CurrentModel", out Model) || Model == null)
            {
                Model = new LockscreenViewModel();
            }
            DataContext = Model;
        }
    
        public MyControl(Model model)
        {
            InitializeComponent();
            Model = model;
            DataContext = Model;
        } 
    }
    Suggestions?

    EDIT:
    By "not visible" I don't mean that the component has its Visibility set to Collapsed, it's not visible because is built in the code-behind and it's never shown anywhere (I need to do this in a background agaent so I don't have any page or graphical stuff)
    Last edited by StepTNT; 2013-12-07 at 16:22.

  2. #2
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    511

    Re: Export a screenshot of a component that's not visible

    I assume that the problem is that you're trying to render XAML content on a background thread which isn't possible. However you can synchronize your code to the "UI-Thread" even when using a background agent.

    You might want to look at the answer provided in post 6 here: http://social.msdn.microsoft.com/For...orum=wpdevelop

    There is also some other helpful information regarding XAML rendering in a background task in that discussion thread.

  3. #3
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    Your reply helped me solving the problem with the exception.
    Following the reply in your link, now I'm able to save the image to the media library (just to check if everything went fine).

    The problem is that the saved image is just plain black.

    Here's the new code:

    Code:
    public static void SaveScreenshot(Model model)
    {            
        Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            try
            {
                var bitmap = new WriteableBitmap(400, 800);            
                var size = new Size(400, 800);
                var rect = new Rect(0, 0, 400, 800);
                var myControl= new Canvas(){Background = new SolidColorBrush(Colors.Red)};
                myControl.Children.Add(new TextBlock(){Text =  "Render me please!"});
                myControl.UpdateLayout();
                myControl.Measure(size);
                myControl.UpdateLayout();   
                myControl.Arrange(rect);
                myControl.UpdateLayout();
                bitmap.Render(lockscreen, new TranslateTransform(){X = 0, Y = 0});
                bitmap.Invalidate();                    
                using (var mediaGallery = new MediaLibrary())
                {
                    using (var stream = new MemoryStream())
                    {                            
                        bitmap.SavePng(stream);
                        stream.Seek(0, SeekOrigin.Begin);
                        mediaGallery.SavePicture(FILE_NAME, stream);
                    }
                }
                MessageBox.Show("Picture saved");
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
        });                        
    }
    Is it normal that the control does never fire the Loaded event?
    Is this somehow related to my problem?

  4. #4
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    511

    Re: Export a screenshot of a component that's not visible

    It seems lots of people are running into issues with this but it's been quite some time since I last worked with this. This article has working code to produce an output so it might be worth a try to take it as a template and work from there: http://stackoverflow.com/questions/1...le-bitmapimage

    One thing in your code that is likely not to work is that the Canvas-Control is used for absolute positioning of child controls and as far as I can see you're not positioning the TextBlock. But given that the Background also isn't rendered you might be facing another issue altogether. Hope the sample code produces something usable for your use-case and that you can adapt it from tile rendering to lockscreen images.

    PS: Another thing I should perhaps mention is that you're very constrained with regards to how much memory you can use in the background. So rendering anything in the device's native screen resolution won't work - 800x480/854x480 will likely be the maximum you can do.

  5. #5
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    The canvas was just a quick sample.
    Changing it to Grid make the render work but it still doesn't render my custom control.

    Please note that I'm not rendering in the background thread yet, so I don't have any memory problem at the moment.

    Here's the new code (the output is a large red image with nothing else inside):

    Code:
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    try
                    {
                        var bitmap = new WriteableBitmap(400, 800);
                        var size = new Size(400, 800);
                        var rect = new Rect(0, 0, 400, 800);                                   
                        var grid = new Grid {Background = new SolidColorBrush(Colors.Red)};
                        var lockscreen = new LockscreenControl(model);                                        
                        grid.Children.Add(lockscreen);
                        grid.Measure(size);
                        grid.Arrange(rect);
                        grid.UpdateLayout();
                        bitmap.Render(grid, new TranslateTransform {X = 0, Y = 0});
                        bitmap.Invalidate();
                        using (var mediaGallery = new MediaLibrary())
                        {
                            using (var stream = new MemoryStream())
                            {
                                bitmap.SaveJpeg(stream, bitmap.PixelWidth, bitmap.PixelHeight,0, 100);
                                stream.Seek(0, SeekOrigin.Begin);
                                mediaGallery.SavePicture(FILE_NAME, stream);
                            }
                        }
                        MessageBox.Show("Picture saved");
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e);
                    }
                });
    Of course, changing from my custom control to a TextBlock makes it render fine.

    I have totally no idea of what's going wrong here :/

  6. #6
    Nokia Developer Champion
    Join Date
    Nov 2011
    Location
    la bouexiere, france
    Posts
    473

    Re: Export a screenshot of a component that's not visible

    what is LockscreenControl?

    i thinks it can't be rendered. Several UI element can't be rendered if they are not in the visual tree...
    Windows 8, Windows phone 8 or Nokia Asha developer? Go to DVLUP

  7. #7
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    It's a custom control that I made.

    Can you please provide some more infos on your last sentence?
    Because this breaks the whole concept of my app and, honestly, it sucks a little bit ..

  8. #8
    Nokia Developer Champion
    Join Date
    Mar 2013
    Posts
    511

    Re: Export a screenshot of a component that's not visible

    Some controls can't be rendered - e.g. the WebBrowser-Control can not render it's contents to a WritableBitmap at all.

    As for your App - it might be that the issue is with the usage of a UserControl instead of using a Grid. Given that your Lifetime events don't fire according to what you told us it's likely that DataBinding won't work either.

    Putting the primitive Controls inside the layout containers directly and setting their data directly without using DataBinding should work. Getting complex layouts done that way is possible albeit more work than with the regular UI.

  9. #9
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    Are you saying that I can just rebuild my UI in C# (by setting properties manually instead of relying on DataBinding) and then call the Render method on that object?
    It seems a lot of work to me, does anyone know why we can't render some kind of objects?

  10. #10
    Nokia Developer Champion
    Join Date
    Nov 2011
    Location
    la bouexiere, france
    Posts
    473

    Re: Export a screenshot of a component that's not visible

    Quote Originally Posted by StepTNT View Post
    Can you please provide some more infos on your last sentence?
    Because this breaks the whole concept of my app and, honestly, it sucks a little bit ..
    I imagine...
    Unfortunately, i haven't a lot of information and i never really understand. It's observation and few information i found on internet.... sorry.

    I my case, i have try with richtextbox. If it's not in the visual tree, impossible to render it => impossible to use it in a background agent.
    Maybe it's just a element used in your custom control which make problem? Which ui element do you use?
    Windows 8, Windows phone 8 or Nokia Asha developer? Go to DVLUP

  11. #11
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    For now I'm just using a custom component with an Image (from Telerik's RadControl) and 2 custom controls which contain just some TextBox.

    Having to rewrite everything "by hand" forces me to deal with a lot of casting problems (I worked a lot with inheritance), plus the fact that I need to make "public" every xaml property of my custom controls.

    I know that's not your fault but I'm quite disappointed :\

  12. #12
    Nokia Developer Champion
    Join Date
    Nov 2011
    Location
    la bouexiere, france
    Posts
    473

    Re: Export a screenshot of a component that's not visible

    You want do it in a background agent? Or only when the application is displayed?
    Windows 8, Windows phone 8 or Nokia Asha developer? Go to DVLUP

  13. #13
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    Background agent.
    Now I'm doing it in the application just to see if everything works, but the goal is to have it working in a Background Agent

  14. #14
    Nokia Developer Champion
    Join Date
    Nov 2011
    Location
    la bouexiere, france
    Posts
    473

    Re: Export a screenshot of a component that's not visible

    have you try to render without a grid?

    Code:
     
    var lockscreen = new LockscreenControl(model);                                        
    lockscreen .Measure(size);
    lockscreen .Arrange(rect);          
    bitmap.Render(lockscreen , new TranslateTransform {X = 0, Y = 0});
    bitmap.Invalidate();
    Windows 8, Windows phone 8 or Nokia Asha developer? Go to DVLUP

  15. #15
    Registered User
    Join Date
    Sep 2013
    Posts
    45

    Re: Export a screenshot of a component that's not visible

    That's the first thing that I've tried, the result is a plain black picture

Similar Threads

  1. Get a screenshot
    By er_benji in forum Symbian Media (Closed)
    Replies: 14
    Last Post: 2012-02-22, 12:39
  2. Take a screenshot and save it .
    By droopyar in forum Symbian Media (Closed)
    Replies: 1
    Last Post: 2011-11-27, 09:28
  3. Screenshot
    By mohitrb1 in forum Mobile Java General
    Replies: 22
    Last Post: 2010-03-26, 14:03
  4. screenshot not possible
    By _Askin_ in forum Mobile Web Server
    Replies: 4
    Last Post: 2008-05-30, 07:27
  5. Carbide developer wont import EXPORT commands from EXPORT.MAKE
    By jimgilmour1 in forum Carbide.c++ IDE and plug-ins (Closed)
    Replies: 3
    Last Post: 2006-10-26, 06:27

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×