Screenshot your WPF application

Published 03.09.2009 06:17 AM by Admin in WPF
Tags: ,

Often we need a way to capture picture of UI. For example if error occurs in our application we can take picture of UI and send this picture in error report.

Usual way in windows forms is calling Graphic.CopyFromScreen method. This way is not work very well in WPF. If we have some transparent controls on form this method will save image under transparent control.

So in WPF we will use GDI+ to take picture of UI. We have internal class NativeMethods:

 internal class NativeMethods

    {

        [DllImport("user32.dll")]

        public extern static IntPtr GetDesktopWindow();

 

        [System.Runtime.InteropServices.DllImport("user32.dll")]

        public static extern IntPtr GetWindowDC(IntPtr hwnd);

 

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]

        public static extern IntPtr GetForegroundWindow();

 

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]

        public static extern UInt64 BitBlt

             (IntPtr hDestDC,

             int x,

             int y,

             int nWidth,

             int nHeight,

             IntPtr hSrcDC,

             int xSrc,

             int ySrc,

             System.Int32 dwRop);

    }

And we take picture UI by calling this method :

 public void SaveScreen()

        {

            Bitmap myImage = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width,

            Screen.PrimaryScreen.WorkingArea.Height);

 

            Graphics gr1 = Graphics.FromImage(myImage);

            IntPtr dc1 = gr1.GetHdc();

 

            IntPtr dc2 = NativeMethods.GetWindowDC(NativeMethods.GetForegroundWindow());

 

 

            NativeMethods.BitBlt(dc1, Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, Screen.PrimaryScreen.Bounds.Width,

                 Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376);

            gr1.ReleaseHdc(dc1);

            myImage.Save("screen.png", ImageFormat.Png);

        }

 

You can download Demo application :

ScreenShotWPF.rar (38.14 kb)

Currently rated 2.5 by 4 people

  • Currently 2.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

If you are interesting to learn more about Validation Application Block you can always download Hand on Labs about VAB: http://www.microsoft.com/downloads/details.aspx?FamilyID=2C34A9CB-17CF-4AEC-8DE6-EEACBBB74413&displaylang=en

In these labs you will find very good explanation about using VAB integration with WCF, but what if you are manually creating proxy instead using add service reference?

In this article I will show you how to use VAB 4.1 with WCF and manually generated proxy.

My solution structure looks like this :

Picture1

I have created one project called DataContracts where all DataContract classes and Validation rules are defined. Code for that class looks like this :

 public class Customer

    {

        [StringLengthValidator(1, 25,

           MessageTemplateResourceType = typeof(Resources),

           MessageTemplateResourceName = "FirstNameMessage")]

        [NotNullValidator]

        public string FirstName { get; set; }

        [StringLengthValidator(1, 25,

          MessageTemplateResourceType = typeof(Resources),

          MessageTemplateResourceName = "LastNameMessage")]

        [NotNullValidator]

        public string LastName { get; set; }

        public string Nickname { get; set; }

        public DateTime BirthDate { get; set; }

        [ObjectValidator]

        public Address Address { get; set; }

 

        public Customer()

        {

            this.Address=new Address();

        }

    }

 

    public class Address

    {

        [StringLengthValidator(1, 50)]

        public string StreetName { get; set; }

 

        public int Number { get; set; }

        [DomainValidator("AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR", "PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI", "VA", "WA", "WV", "WI", "WY",

            MessageTemplate = "Value is not a valid US state two-letter abbreviation.")]

        public string USState { get; set; }

 

    }

I have manually created proxy class. It looks like this :

  public class CustomerClientProxy : ClientBase<ICustomerService>, ICustomerService

    {

 

        public string ProcessCustomer(DataContracts.Customer customer, string notes)

        {

            return Channel.ProcessCustomer(customer, notes);

        }

 

    }

In service contracts project I have defined interface that WCF will use. We must decorate method signature in interface with  validation attribute that define FaultContract for method.

We are using  ValidationFault class that is defined in VAB for error transporting to the client side.

  [FaultContract(typeof(ValidationFault))]

        string ProcessCustomer(

            Customer customer, [StringLengthValidator(1, 100,

                MessageTemplate = "The notes must be 1 to 100 characters long.")]

            string notes);

In web config file for WCF service we must add new behaviorConfiguration for Endpoint. ValidationElement is used to perform some validation actions on WCF before calling method on WCF.

<behaviorExtensions>
<add name="validation" type="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.ValidationElement, 
        Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF, Version=4.1.0.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35" />
</behaviorExtensions>

On client side I have one standard WPF application with basic App.Config where is just defined ABC for WCF. (address, binding, contract)

I have bind client side textboxes on the form with my Customer class.  After that I have some code to catch exceptions throw by the server and show that exceptions in simple message box.

using (Proxy.CustomerClientProxy client = new Proxy.CustomerClientProxy())

            {

                try

                {

 

                    Customer cust=((Customer)this.DataContext);

 

                    client.ProcessCustomer(cust, "My message!!!");

                }

                catch (FaultException<ValidationFault> fex)

                {

                    StringBuilder builder = new StringBuilder();

                    builder.AppendLine("Validation error invoking service:
"
);

                    foreach (ValidationDetail result in fex.Detail.Details)

                    {

                        builder.AppendLine(

                            string.Format("{0}: {1}
"
, result.Key, result.Message));

                    }

 

                    MessageBox.Show(builder.ToString());

 

                }

 

                catch (Exception ex)

                {

                    MessageBox.Show(ex.StackTrace.ToString());

                }

            }

After I run my application and enter some incorrect values I get message box :

Picture2

 

Here is complete code :ValidationServiceWCF.rar

Reference : http://www.clariusconsulting.net/blogs/kzu/archive/2007/09/24/WhyweneedanEntLibStandaloneValidationApplicationBlock.aspx

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Radenko Zec Blog

Silverlight, C#, WCF, WPF,NET...