title: Image control ActualWidth correct only after second load - Image Cropper
body: <p>I'm trying to extend crop control from <a href="http://www.codeproject.com/Articles/23158/A-Photoshop-like-Cropping-Adorner-for-WPF" rel="nofollow noreferrer">CodeProject</a> with ability to choose image from disk, display it with <code>Stretch='Uniform'</code> and ability to resize crop area with aspect ratio.</p>
  
  <p>I've done all the modifications, but I have a problem - i must load same image twice to get <code>ActualWidth</code> of Image control.</p>
  
  <p>I've searched over SO (<a href="https://stackoverflow.com/questions/1695101/why-are-actualwidth-and-actualheight-0-0-in-this-case">Why are ActualWidth and ActualHeight 0.0 in this case?</a>) for solutions, but I wasn't able to get this working.</p>
  
  <p>Below is my full code:</p>
  
  <p>windows.xaml:</p>
  
  <pre><code>&lt;Window
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="CroppingTest.WndCroppingTest"
      Title="CroppingTest"
      Width="900" Height="600" Background="OliveDrab"
      SizeChanged="Window_SizeChanged" Loaded="WndCroppingTest_OnLoaded"
      &gt;
      &lt;Grid&gt;
          &lt;Grid.ColumnDefinitions&gt;
              &lt;ColumnDefinition/&gt;
              &lt;ColumnDefinition Width="10"/&gt;
              &lt;ColumnDefinition Width="Auto"/&gt;
          &lt;/Grid.ColumnDefinitions&gt;
          &lt;Grid.RowDefinitions&gt;
              &lt;RowDefinition/&gt;
              &lt;RowDefinition Height="Auto"/&gt;
          &lt;/Grid.RowDefinitions&gt;
          &lt;Grid HorizontalAlignment="Center" VerticalAlignment="Center"&gt;
              &lt;Grid&gt;
                  &lt;Rectangle Fill="White"&gt;
                      &lt;Rectangle.Effect&gt;
                          &lt;DropShadowEffect Opacity="0.5" /&gt;
                      &lt;/Rectangle.Effect&gt;
                  &lt;/Rectangle&gt;
                  &lt;Image x:Name="Crop" Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Center" /&gt;
              &lt;/Grid&gt;
          &lt;/Grid&gt;
          &lt;StackPanel HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Grid.Column="2"&gt;
              &lt;StackPanel.Resources&gt;
                  &lt;Style TargetType="CheckBox"&gt;
                      &lt;Setter Property="Margin" Value="5,5,5,5"/&gt;
                  &lt;/Style&gt;
              &lt;/StackPanel.Resources&gt;
              &lt;Image x:Name="Preview" Width="130" Height="100" Margin="0,5,5,0"/&gt;
              &lt;Button Content="Open" HorizontalAlignment="Stretch" Margin="0,10" Click="OnOpen"/&gt;
              &lt;Button Content="Save" HorizontalAlignment="Stretch" Margin="0,10" Click="OnSave"/&gt;
          &lt;/StackPanel&gt;
          &lt;TextBlock HorizontalAlignment="Stretch" Margin="5,0,0,5" x:Name="tblkClippingRectangle" VerticalAlignment="Top" Width="Auto" Height="Auto" Grid.Row="1" Foreground="#FFFFFFFF" Text="ClippingRectangle" TextWrapping="Wrap"/&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>code behind:</p>
  
  <pre><code>using System;
  using System.Diagnostics;
  using System.IO;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Documents;
  using System.Windows.Media.Imaging;
  using DAP.Adorners;
  using Microsoft.Win32;
  
  namespace CroppingTest
  {
      /// &lt;summary&gt;
      /// Interaction logic for Window1.xaml
      /// &lt;/summary&gt;
  
      public partial class WndCroppingTest
      {
          CroppingAdorner _clp;
          FrameworkElement _felCur;
  
          public WndCroppingTest()
          {
              InitializeComponent();
          }
  
          private string _s;
  
          public WndCroppingTest(string source)
          {
              _s = source;
              InitializeComponent();
  
          }
  
          private void RemoveCropFromCur()
          {
              AdornerLayer aly = AdornerLayer.GetAdornerLayer(_felCur);
              aly.Remove(_clp);
          }
  
          private void AddCropToImage(Image fel)
          {
              if (_felCur != null)
              {
                  RemoveCropFromCur();
              }
  
              Size s = new Size(80,120);
              double ratio = s.Width/s.Height;
              Rect r = new Rect();
              if (ratio &lt; 1)
              {
                  r.Height = fel.ActualHeight;
                  r.Width = fel.ActualHeight*ratio;
                  r.Y = 0;
                  r.X = (fel.ActualWidth - r.Width)/2;
              }
              else
              {
                  r.Width = fel.ActualWidth;
                  r.Height = fel.ActualWidth / ratio;
                  r.X = 0;
                  r.Y = (fel.ActualHeight - r.Height) / 2;
              }
              AdornerLayer aly = AdornerLayer.GetAdornerLayer(fel);
              _clp = new CroppingAdorner(fel, r,true);
              aly.Add(_clp);
              Preview.Source = _clp.BpsCrop();
              _clp.CropChanged += CropChanged;
              _felCur = fel;
          }
  
          private void RefreshCropImage()
          {
              if (_clp != null)
              {
                  Rect rc = _clp.ClippingRectangle;
  
                  tblkClippingRectangle.Text = string.Format(
                      "Clipping Rectangle: ({0:N1}, {1:N1}, {2:N1}, {3:N1})",
                      rc.Left,
                      rc.Top,
                      rc.Right,
                      rc.Bottom);
                  Preview.Source = _clp.BpsCrop();
              }
          }
  
          private void CropChanged(Object sender, RoutedEventArgs rea)
          {
              RefreshCropImage();
          }
  
          private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
          {
              RefreshCropImage();
          }
  
          private void OnOpen(object sender, RoutedEventArgs e)
          {
              OpenFileDialog openfile = new OpenFileDialog
              {
                  //Filter = "JPEG (*.jpeg)|*.jpeg|PNG (*.png)|*.png|JPG (*.jpg)|*.jpg"
                  Filter = "Obrazy (*.jpeg, *.png, *.jpg)|*.jpeg;*.png;*.jpg"
              };
              bool? result = openfile.ShowDialog();
              if (result == true)
              {
                  //MessageBox.Show(openfile.FileName);
  
                  var source = openfile.FileName;
                  Crop.Source= new BitmapImage(new Uri(source));
                  AddCropToImage(Crop);
                  RefreshCropImage();
              }
          }
  
          private void OnSave(object sender, RoutedEventArgs e)
          {
              SaveFileDialog dlg = new SaveFileDialog
              {
                  FileName = "Avatar",
                  DefaultExt = ".png",
                  Filter = "PNGi (.png)|*.png"
              };
              bool? result = dlg.ShowDialog();
              if (result == true)
              {
                  string filename = dlg.FileName;
  
                  using (var fileStream = new FileStream(filename, FileMode.Create))
                  {
                      BitmapEncoder encoder = new PngBitmapEncoder();
                      encoder.Frames.Add(BitmapFrame.Create(_clp.BpsCrop()));
                      encoder.Save(fileStream);
                  }
              }
          }
  
          private void WndCroppingTest_OnLoaded(object sender, RoutedEventArgs e)
          {
              if (_s != null)
              {
                  Crop.Source = new BitmapImage(new Uri(_s));
                  AddCropToImage(Crop);
                  RefreshCropImage();
              }
          }
      }
  }
  </code></pre>
  
  <p>CroppingAdorner:</p>
  
  <pre><code>using System;
  using System.Diagnostics;
  using System.Drawing;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Controls.Primitives;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Shapes;
  using Brush = System.Windows.Media.Brush;
  using Brushes = System.Windows.Media.Brushes;
  using Color = System.Windows.Media.Color;
  using Image = System.Windows.Controls.Image;
  using Pen = System.Windows.Media.Pen;
  using Point = System.Drawing.Point;
  using Size = System.Windows.Size;
  
  namespace DAP.Adorners
  {
      public class CroppingAdorner : Adorner
      {
          #region Private variables
          // Width of the thumbs.  I know these really aren't "pixels", but px
          // is still a good mnemonic.
          private const int _cpxThumbWidth = 6;
  
          // PuncturedRect to hold the "Cropping" portion of the adorner
          private PuncturedRect _prCropMask;
  
          // Canvas to hold the thumbs so they can be moved in response to the user
          private Canvas _cnvThumbs;
  
          // Cropping adorner uses Thumbs for visual elements.  
          // The Thumbs have built-in mouse input handling.
          private CropThumb _crtTopLeft, _crtTopRight, _crtBottomLeft, _crtBottomRight;
          //private CropThumb _crtTop, _crtLeft, _crtBottom, _crtRight;
  
          // To store and manage the adorner's visual children.
          private VisualCollection _vc;
  
          // DPI for screen
          private static double s_dpiX, s_dpiY;
  
  
          private Size _originalSize, _controlSize;
  
          private Image _i;
  
          private ImageSource _s;
          private BitmapImage _b;
          #endregion
  
          #region Properties
          public Rect ClippingRectangle
          {
              get
              {
                  return _prCropMask.RectInterior;
              }
          }
          #endregion
  
          #region Routed Events
          public static readonly RoutedEvent CropChangedEvent = EventManager.RegisterRoutedEvent(
              "CropChanged",
              RoutingStrategy.Bubble,
              typeof(RoutedEventHandler),
              typeof(CroppingAdorner));
  
          public event RoutedEventHandler CropChanged
          {
              add
              {
                  AddHandler(CropChangedEvent, value);
              }
              remove
              {
                  RemoveHandler(CropChangedEvent, value);
              }
          }
          #endregion
  
          #region Dependency Properties
          static public DependencyProperty FillProperty = Shape.FillProperty.AddOwner(typeof(CroppingAdorner));
  
          public Brush Fill
          {
              get { return (Brush)GetValue(FillProperty); }
              set { SetValue(FillProperty, value); }
          }
  
          private static void FillPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
          {
              CroppingAdorner crp = d as CroppingAdorner;
  
              if (crp != null)
              {
                  crp._prCropMask.Fill = (Brush)args.NewValue;
              }
          }
          #endregion
  
          #region Constructor
          static CroppingAdorner()
          {
              Color clr = Colors.Black;
              Graphics g = Graphics.FromHwnd((IntPtr)0);
  
              s_dpiX = g.DpiX;
              s_dpiY = g.DpiY;
              clr.A = 80;
              FillProperty.OverrideMetadata(typeof(CroppingAdorner),
                  new PropertyMetadata(
                      new SolidColorBrush(clr),
                      FillPropChanged));
          }
  
          public CroppingAdorner(Image sourceImage, Rect rcInit, bool fixedRatio = false)
              : base(sourceImage)
          {
              _fixedRatio = fixedRatio;
              _ratio = rcInit.Width/rcInit.Height;
              _i = sourceImage;
              _s = sourceImage.Source;
              try
              {
                  _b = (BitmapImage) sourceImage.Source;
              }
              catch (Exception e)
              {
                  Debug.WriteLine(e);
              }
  
              try
              {
                  _originalSize = new Size(_b.PixelWidth, _b.PixelHeight);
              }
              catch (Exception e)
              {
                  _originalSize = new Size(1,1);
              }
              _controlSize = new Size(sourceImage.ActualWidth, sourceImage.ActualHeight);
              _vc = new VisualCollection(this);
              _prCropMask = new PuncturedRect();
              _prCropMask.IsHitTestVisible = false;
              _prCropMask.RectInterior = rcInit;
              _prCropMask.Fill = Fill;
              _vc.Add(_prCropMask);
              _cnvThumbs = new Canvas();
              _cnvThumbs.HorizontalAlignment = HorizontalAlignment.Stretch;
              _cnvThumbs.VerticalAlignment = VerticalAlignment.Stretch;
  
              _vc.Add(_cnvThumbs);
              //BuildCorner(ref _crtTop, Cursors.SizeNS);
              //BuildCorner(ref _crtBottom, Cursors.SizeNS);
              //BuildCorner(ref _crtLeft, Cursors.SizeWE);
              //BuildCorner(ref _crtRight, Cursors.SizeWE);
              BuildCorner(ref _crtTopLeft, Cursors.SizeNWSE);
              BuildCorner(ref _crtTopRight, Cursors.SizeNESW);
              BuildCorner(ref _crtBottomLeft, Cursors.SizeNESW);
              BuildCorner(ref _crtBottomRight, Cursors.SizeNWSE);
  
              // Add handlers for Cropping.
              _crtBottomLeft.DragDelta += HandleBottomLeft;
              _crtBottomRight.DragDelta += HandleBottomRight;
              _crtTopLeft.DragDelta += HandleTopLeft;
              _crtTopRight.DragDelta += HandleTopRight;
              //_crtTop.DragDelta += HandleTop;
              //_crtBottom.DragDelta += HandleBottom;
              //_crtRight.DragDelta += HandleRight;
              //_crtLeft.DragDelta += HandleLeft;
  
              //add eventhandler to drag and drop 
              sourceImage.MouseLeftButtonDown += Handle_MouseLeftButtonDown;
              sourceImage.MouseLeftButtonUp += Handle_MouseLeftButtonUp;
              sourceImage.MouseMove += Handle_MouseMove;
  
              // We have to keep the clipping interior withing the bounds of the adorned element
              // so we have to track it's size to guarantee that...
              FrameworkElement fel = sourceImage;
              fel.SizeChanged += AdornedElement_SizeChanged;
          }
          #endregion
  
          #region Drag and drop handlers
  
          Double OrigenX;
          Double OrigenY;
          private readonly bool _fixedRatio;
          private double _ratio;
  
          //  generic handler move selection with Drag'n'Drop
          private void HandleDrag(double dx, double dy)
          {
              Rect rcInterior = _prCropMask.RectInterior;
              rcInterior = new Rect(
                 dx,
                 dy,
                  rcInterior.Width,
                  rcInterior.Height);
  
              _prCropMask.RectInterior = rcInterior;
              SetThumbs(_prCropMask.RectInterior);
              RaiseEvent(new RoutedEventArgs(CropChangedEvent, this));
          }
  
          private void Handle_MouseMove(object sender, MouseEventArgs args)
          {
              Image Marco = sender as Image;
              if (Marco != null &amp;&amp; Marco.IsMouseCaptured)
              {
                  Double x = args.GetPosition(Marco).X; //posición actual cursor
                  Double y = args.GetPosition(Marco).Y;
                  Double _x = _prCropMask.RectInterior.X; // posición actual esquina superior izq del marco interior
                  Double _y = _prCropMask.RectInterior.Y;
                  Double _width = _prCropMask.RectInterior.Width; //dimensiones del marco interior
                  Double _height = _prCropMask.RectInterior.Height;
  
                  //si el click es dentro del marco interior
                  if (((x &gt; _x) &amp;&amp; (x &lt; (_x + _width))) &amp;&amp; ((y &gt; _y) &amp;&amp; (y &lt; (_y + _height))))
                  {
                      //calculamos la diferencia de la posición actual del cursor con respecto al punto de origen del arrastre
                      //y se la añadimos a la esquina sup. izq. del marco interior.
                      _x = _x + (x - OrigenX);
                      _y = _y + (y - OrigenY);
  
                      //comprobamos si es posible mover sin salirse del marco exterior por ninguna de sus dimensiones
                      //no supera el borde izquierdo de la imagen: !(_x &lt; 0)
                      if (_x &lt; 0)
                      {
                          _x = 0;
                      }
                      //no supera el borde derecho de la imagen: !((_x + _width) &gt; Marco.Width)
                      if ((_x + _width) &gt; Marco.ActualWidth)
                      {
                          _x = Marco.ActualWidth - _width;
                      }
                      //no supera el borde superior de la imagen: !(_y&lt;0)
                      if (_y &lt; 0)
                      {
                          _y = 0;
                      }
                      //no supera el borde inferior de la imagen: !((_y + _height) &gt; Marco.Height)
                      if ((_y + _height) &gt; Marco.ActualHeight)
                      {
                          _y = Marco.ActualHeight - _height;
                      }
  
                      //asignamos nuevo punto origen del arrastre y movemos el marco interior
                      OrigenX = x;
                      OrigenY = y;
                      HandleDrag(_x, _y);
  
                  }
              }
  
          }
  
          private void Handle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
          {
              Image Marco = sender as Image;
              if (Marco != null)
              {
                  Marco.CaptureMouse();
                  OrigenX = e.GetPosition(Marco).X; //iniciamos las variables en el punto de origen del arrastre
                  OrigenY = e.GetPosition(Marco).Y;
              }
          }
  
          private void Handle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
          {
              Image Marco = sender as Image;
              if (Marco != null)
              {
                  Marco.ReleaseMouseCapture();
              }
          }
          #endregion
  
          #region Thumb handlers
          // Generic handler for Cropping
          private void HandleThumb(
              double drcL,
              double drcT,
              double drcW,
              double drcH,
              double dx,
              double dy)
          {
              Rect rcInterior = _prCropMask.RectInterior;
  
              if (rcInterior.Width + drcW * dx &lt; 0)
              {
                  dx = -rcInterior.Width / drcW;
              }
  
              if (rcInterior.Height + drcH * dy &lt; 0)
              {
                  dy = -rcInterior.Height / drcH;
              }
  
              rcInterior = new Rect(
                  rcInterior.Left + drcL * dx,
                  rcInterior.Top + drcT * dy,
                  rcInterior.Width + drcW * dx,
                  rcInterior.Height + drcH * dy);
  
              if (_fixedRatio)
              {
                  if (_ratio &lt; 1)
                  {
                      if (rcInterior.Height &gt; _i.ActualHeight)
                      {
                          rcInterior.Height = _i.ActualHeight;
                      }
                      rcInterior.Width = rcInterior.Height * _ratio;
                  }
                  else
                  {
                      if (rcInterior.Width &gt; _i.ActualWidth)
                      {
                          rcInterior.Width = _i.ActualWidth;
                      }
                      rcInterior.Height = rcInterior.Width / _ratio;
                  }
              }
  
              _prCropMask.RectInterior = rcInterior;
              SetThumbs(_prCropMask.RectInterior);
              RaiseEvent( new RoutedEventArgs(CropChangedEvent, this));
          }
  
          // Handler for Cropping from the bottom-left.
          private void HandleBottomLeft(object sender, DragDeltaEventArgs args)
          {
              if (sender is CropThumb)
              {
                  HandleThumb(
                      1, 0, -1, 1,
                      args.HorizontalChange,
                      args.VerticalChange);
              }
          }
  
          // Handler for Cropping from the bottom-right.
          private void HandleBottomRight(object sender, DragDeltaEventArgs args)
          {
              if (sender is CropThumb)
              {
                  HandleThumb(
                      0, 0, 1, 1,
                      args.HorizontalChange,
                      args.VerticalChange);
              }
          }
  
          // Handler for Cropping from the top-right.
          private void HandleTopRight(object sender, DragDeltaEventArgs args)
          {
              if (sender is CropThumb)
              {
                  HandleThumb(
                      0, 1, 1, -1,
                      args.HorizontalChange,
                      args.VerticalChange);
              }
          }
  
          // Handler for Cropping from the top-left.
          private void HandleTopLeft(object sender, DragDeltaEventArgs args)
          {
              if (sender is CropThumb)
              {
                  HandleThumb(
                      1, 1, -1, -1,
                      args.HorizontalChange,
                      args.VerticalChange);
              }
          }
  
          #endregion
  
          #region Other handlers
          private void AdornedElement_SizeChanged(object sender, SizeChangedEventArgs e)
          {
              FrameworkElement fel = sender as FrameworkElement;
              Rect rcInterior = _prCropMask.RectInterior;
              bool fFixupRequired = false;
              double
                  intLeft = rcInterior.Left,
                  intTop = rcInterior.Top,
                  intWidth = rcInterior.Width,
                  intHeight = rcInterior.Height;
  
              if (rcInterior.Left &gt; fel.RenderSize.Width)
              {
                  intLeft = fel.RenderSize.Width;
                  intWidth = 0;
                  fFixupRequired = true;
              }
  
              if (rcInterior.Top &gt; fel.RenderSize.Height)
              {
                  intTop = fel.RenderSize.Height;
                  intHeight = 0;
                  fFixupRequired = true;
              }
  
              if (rcInterior.Right &gt; fel.RenderSize.Width)
              {
                  intWidth = Math.Max(0, fel.RenderSize.Width - intLeft);
                  fFixupRequired = true;
              }
  
              if (rcInterior.Bottom &gt; fel.RenderSize.Height)
              {
                  intHeight = Math.Max(0, fel.RenderSize.Height - intTop);
                  fFixupRequired = true;
              }
              if (fFixupRequired)
              {
                  _prCropMask.RectInterior = new Rect(intLeft, intTop, intWidth, intHeight);
              }
          }
          #endregion
  
          #region Arranging/positioning
          private void SetThumbs(Rect rc)
          {
              _crtBottomRight.SetPos(rc.Right, rc.Bottom);
              _crtTopLeft.SetPos(rc.Left, rc.Top);
              _crtTopRight.SetPos(rc.Right, rc.Top);
              _crtBottomLeft.SetPos(rc.Left, rc.Bottom);
              //_crtTop.SetPos(rc.Left + rc.Width / 2, rc.Top);
              //_crtBottom.SetPos(rc.Left + rc.Width / 2, rc.Bottom);
              //_crtLeft.SetPos(rc.Left, rc.Top + rc.Height / 2);
              //_crtRight.SetPos(rc.Right, rc.Top + rc.Height / 2);
          }
  
          // Arrange the Adorners.
          protected override Size ArrangeOverride(Size finalSize)
          {
              Rect rcExterior = new Rect(0, 0, AdornedElement.RenderSize.Width, AdornedElement.RenderSize.Height);
              _prCropMask.RectExterior = rcExterior;
              Rect rcInterior = _prCropMask.RectInterior;
              _prCropMask.Arrange(rcExterior);
  
              SetThumbs(rcInterior);
              _cnvThumbs.Arrange(rcExterior);
              return finalSize;
          }
          #endregion
  
          #region Public interface
          public BitmapSource BpsCrop()
          {
              Thickness margin = AdornerMargin();
              Rect rcInterior = _prCropMask.RectInterior;
  
              Point pxFromSize = UnitsToPx(rcInterior.Width, rcInterior.Height);
  
              // It appears that CroppedBitmap indexes from the upper left of the margin whereas RenderTargetBitmap renders the
              // control exclusive of the margin.  Hence our need to take the margins into account here...
  
              Point pxFromPos = UnitsToPx(rcInterior.Left, rcInterior.Top);
              Point pxWhole = UnitsToPx(AdornedElement.RenderSize.Width, AdornedElement.RenderSize.Height);
              pxFromSize.X = Math.Max(Math.Min(pxWhole.X - pxFromPos.X, pxFromSize.X), 0);
              pxFromSize.Y = Math.Max(Math.Min(pxWhole.Y - pxFromPos.Y, pxFromSize.Y), 0);
              if (pxFromSize.X == 0 || pxFromSize.Y == 0)
              {
                  return null;
              }
  
              var Width = _i.ActualWidth;
              var Height = _i.ActualHeight;
  
              int x = (int)(rcInterior.Left * _originalSize.Width / Width);
              int y = (int)(rcInterior.Top * _originalSize.Height / Height);
  
              int xx = (int)((rcInterior.Width) * _originalSize.Width / Width);
              int yy = (int)((rcInterior.Height) * _originalSize.Height / Height);
              Int32Rect rcFrom = new Int32Rect(x, y, xx, yy);
  
              //Int32Rect rcFrom = new Int32Rect(pxFromPos.X, pxFromPos.Y, pxFromSize.X, pxFromSize.Y);
  
              RenderTargetBitmap rtb = new RenderTargetBitmap(pxWhole.X, pxWhole.Y, s_dpiX, s_dpiY, PixelFormats.Default);
              rtb.Render(AdornedElement);
  
              try
              {
                  return new CroppedBitmap(_b, rcFrom);
              }
              catch (Exception e)
              {
                  Debug.WriteLine(e);
                  return new CroppedBitmap(rtb, new Int32Rect(0,0, 100,100));
              }
  
          }
  
          public static Size RelativeSize(double aspectRatio)
          {
              return (aspectRatio &gt; 1)
                  ? new Size(1, 1 / aspectRatio)
                  : new Size(aspectRatio, 1);
          }
          #endregion
  
          #region Helper functions
          private Thickness AdornerMargin()
          {
              Thickness thick = new Thickness(0);
              if (AdornedElement is FrameworkElement)
              {
                  thick = ((FrameworkElement)AdornedElement).Margin;
              }
              return thick;
          }
  
          private void BuildCorner(ref CropThumb crt, Cursor crs)
          {
              if (crt != null) return;
  
              crt = new CropThumb(_cpxThumbWidth);
  
              // Set some arbitrary visual characteristics.
              crt.Cursor = crs;
  
              _cnvThumbs.Children.Add(crt);
          }
  
          private Point UnitsToPx(double x, double y)
          {
              return new Point((int)(x * s_dpiX / 96), (int)(y * s_dpiY / 96));
          }
          #endregion
  
          #region Visual tree overrides
          // Override the VisualChildrenCount and GetVisualChild properties to interface with 
          // the adorner's visual collection.
          protected override int VisualChildrenCount { get { return _vc.Count; } }
          protected override Visual GetVisualChild(int index) { return _vc[index]; }
          #endregion
  
          #region Internal Classes
          class CropThumb : Thumb
          {
              #region Private variables
              int _cpx;
              #endregion
  
              #region Constructor
              internal CropThumb(int cpx)
                  : base()
              {
                  _cpx = cpx;
              }
              #endregion
  
              #region Overrides
              protected override Visual GetVisualChild(int index)
              {
                  return null;
              }
  
              protected override void OnRender(DrawingContext drawingContext)
              {
                  drawingContext.DrawRoundedRectangle(Brushes.White, new Pen(Brushes.Black, 1), new Rect(new Size(_cpx, _cpx)), 1, 1);
              }
              #endregion
  
              #region Positioning
              internal void SetPos(double x, double y)
              {
                  Canvas.SetTop(this, y - _cpx / 2);
                  Canvas.SetLeft(this, x - _cpx / 2);
              }
              #endregion
          }
          #endregion
      }
  
  }
  </code></pre>
  
  <p>and <a href="http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=23158&amp;zep=CroppingAdorner%2FCroppingAdorner%2FPuncturedRect.cs&amp;rzp=%2FKB%2FWPF%2FCropAdorner%2F%2Fcrop_adorner_sources.zip" rel="nofollow noreferrer">PunctedRect</a> (I can't include code here because it exceeds question length limit, sorry for adding link)</p>
  
  <p>What I'm trying to create is cropping tool that will work on Win7 and will allow me to select portion of image with aspect ratio.</p>
  
  <p>As I wrote before I've tried fixing that ActualWidth problem, but I wasn't able to. How this can be fixed?</p>
  
  <p>Can anyone suggest alternative (free) control that will have described functionality? There are many WUP (Windows Universal Platform) apps and controls, but I need Win7 compatible. </p>