Leadtools.Forms.Ocr Namespace > IOcrPage Interface : HitTestZone Method |
'Usage Dim instance As IOcrPage Dim point As LeadPoint Dim value As Integer value = instance.HitTestZone(point)
function Leadtools.Forms.Ocr.IOcrPage.HitTestZone( point )
You can use this method to check whether a zone (either added manually or automatically) is under a given test point. For example, if you have a Windows Forms based application with the current IOcrPage in a Leadtools.WinForms.RasterImageViewer control. You might want to draw the zones on the surface of the viewer. For this, you can use the GetZoneBoundsInPixels methods. If you want to allow the user to click with the mouse on the viewer to select and de-select zones, you can use HitTestZone.
' Assume Form1 is a Windwos.Forms form in your application ' The OCR engine we are using Private _ocrEngine As IOcrEngine Private _ocrDocument As IOcrDocument ' Our raster image viewer instance Private _viewer As RasterImageViewer Public Sub New() InitializeComponent() ' Initialize the raster image viewer ' Turn on use DPI, center the image, add border padding and frame shadow to show that our calculations will be ' independent on all of those extra options _viewer = New RasterImageViewer() _viewer.Dock = DockStyle.Fill _viewer.BackColor = SystemColors.AppWorkspace _viewer.UseDpi = True _viewer.BorderPadding.All = 8 _viewer.FrameSize = New SizeF(1, 1) _viewer.FrameShadowSize = New SizeF(2, 2) _viewer.SizeMode = RasterPaintSizeMode.Normal _viewer.HorizontalAlignMode = RasterPaintAlignMode.Center _viewer.VerticalAlignMode = RasterPaintAlignMode.Center _viewer.AutoDisposeImages = True _viewer.InteractiveMode = RasterViewerInteractiveMode.None ' Turn on scale to gray painting in the viewer Dim props As RasterPaintProperties = _viewer.PaintProperties props.PaintDisplayMode = props.PaintDisplayMode Or RasterPaintDisplayModeFlags.ScaleToGray _viewer.PaintProperties = props ' Subscribe to the viewer events we need AddHandler _viewer.KeyDown, AddressOf _viewer_KeyDown AddHandler _viewer.MouseDown, AddressOf _viewer_MouseDown AddHandler _viewer.PostImagePaint, AddressOf _viewer_PostImagePaint Controls.Add(_viewer) _viewer.BringToFront() ' Create and startup the OCR engine _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.Plus, False) _ocrEngine.Startup(Nothing, Nothing, Nothing, Nothing) ' Create the OCR document _ocrDocument = _ocrEngine.DocumentManager.CreateDocument() ' Load an image into the document Dim tifFileName As String = Path.Combine(LEAD_VARS.ImagesDir, "Ocr1.tif") Dim ocrPage As IOcrPage = _ocrDocument.Pages.AddPage(tifFileName, Nothing) ' Do auto zone ocrPage.AutoZone(Nothing) ' AutoZone does not specify a name for the zones, so loop through all the zones and set their names ' to a unique value. We will use the name in the paint code later Dim ocrZones As IOcrZoneCollection = ocrPage.Zones For i As Integer = 0 To ocrZones.Count - 1 Dim ocrZone As OcrZone = ocrZones(i) ' Construct the name from the ID ocrZone.Name = String.Format("Zone {0}", ocrZone.Id) ocrZones(i) = ocrZone Next ' Show the same image in the viewer _viewer.Image = ocrPage.GetRasterImage() ' Note, the image we got from GetRasterImage is a copy of the image in the engine ' Since we set teh AutoDisposeImages of the viewer to "true", the image will be disposed ' when the viewer is disposed at application termination Text = "+ to zoom in, - to zoom out, enter to return to 100%. Select the zones with the mouse" End Sub Protected Overrides Sub OnFormClosed(ByVal e As FormClosedEventArgs) ' Destroy the document _ocrDocument.Dispose() ' Shutdown the OCR engine _ocrEngine.Shutdown() _ocrEngine.Dispose() MyBase.OnFormClosed(e) End Sub Private Sub _viewer_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Const zoomRatio As Double = 1.2 Dim scaleFactor As Double = _viewer.ScaleFactor Select Case (e.KeyCode) Case Keys.Add, Keys.Oemplus ' Zoon in scaleFactor *= zoomRatio e.Handled = True Case Keys.Subtract, Keys.OemMinus ' Zone out scaleFactor /= zoomRatio e.Handled = True Case Keys.Enter scaleFactor = 1 e.Handled = True End Select Const minimumScaleFactor As Double = 0.05 Const maximumScaleFactor As Double = 11 scaleFactor = Math.Max(minimumScaleFactor, Math.Min(maximumScaleFactor, scaleFactor)) ' Check if scale factor has changed If (scaleFactor <> _viewer.ScaleFactor) Then _viewer.BeginUpdate() ' Yes, zoom keeping the center of the image ' Get what you see in physical coordinates Dim rc As Rectangle = Rectangle.Intersect(_viewer.PhysicalViewRectangle, _viewer.ClientRectangle) ' Get the center of what you see in physical coordinates Dim center As New PointF(rc.Left + rc.Width \ 2, rc.Top + rc.Height \ 2) Dim t As New Transformer(_viewer.Transform) ' Get the center of what you see in logical coordinates center = t.PointToLogical(center) _viewer.ScaleFactor = scaleFactor ' Bring the original center into the view center t = New Transformer(_viewer.Transform) ' Get the center of what you saw before the zoom in physical coordinates center = t.PointToPhysical(center) ' Bring the old center into the center of the view _viewer.CenterAtPoint(Point.Round(center)) _viewer.EndUpdate() End If End Sub Private Sub _viewer_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) ' Perform hit-testing on the zones If (Not _ocrEngine Is Nothing) AndAlso (_ocrEngine.IsStarted) AndAlso (_ocrDocument.Pages.Count > 0) AndAlso e.Button = Windows.Forms.MouseButtons.Left Then ' Get the transform of the viewer ' Use the transform that takes the DPI into consideration since we turned that on Using matrix As Matrix = _viewer.GetTransformWithDpi() Dim t As New Transformer(matrix) ' Convert the mouse click coordinates from physical (viewer) to logical (image) Dim point As New PointF(e.X, e.Y) point = t.PointToLogical(point) ' Hit test the zones ' An alternitave to calling HitTestZone is to loop through all the zones ' and get the value of .Bounds in pixels, then check if the point is inside ' the boundaries. Dim ocrPage As IOcrPage = _ocrDocument.Pages(0) Dim lPoint As LeadPoint = New LeadPoint(CType(point.X, Integer), CType(point.Y, Integer)) Dim zoneIndex As Integer = ocrPage.HitTestZone(New LogicalPoint(lPoint)) If (zoneIndex <> -1) Then ' We hit a zone, loop through all the zones, unselect all but the hit tested zone For index As Integer = 0 To ocrPage.Zones.Count - 1 ' Since OcrZone is a structure, we cannot simply do ' ocrZone.Zones[index].Selected = value ' We have to get a copy of the structure, modify it and set it back Dim ocrZone As OcrZone = ocrPage.Zones(index) If (index <> zoneIndex) Then ocrZone.Selected = False Else ocrZone.Selected = True End If ocrPage.Zones(index) = ocrZone Next ' Re-paint the viewer to show the new zones _viewer.Invalidate() End If End Using End If End Sub Private Sub _viewer_PostImagePaint(ByVal sender As Object, ByVal e As PaintEventArgs) ' Draw the zones on the viewer in their correct location If (Not _ocrEngine Is Nothing) AndAlso (_ocrEngine.IsStarted) AndAlso (_ocrDocument.Pages.Count > 0) Then ' Get the transform of the viewer ' Use the transform that takes the DPI into consideration since we turned that on Using matrix As Matrix = _viewer.GetTransformWithDpi() Dim t As New Transformer(matrix) Dim ocrPage As IOcrPage = _ocrDocument.Pages(0) Dim normalPen As New Pen(Color.Blue, 1) Dim selectedPen As New Pen(Color.Red, 2) selectedPen.DashStyle = DashStyle.Dash For Each ocrZone As OcrZone In ocrPage.Zones ' Get the zone bounds in pixels ' You can also use ocrPage.GetZoneBoundsInPixels here Dim ltzoneBounds As LeadRect = ocrZone.Bounds.ToRectangle(ocrPage.DpiX, ocrPage.DpiY) Dim zoneBounds As RectangleF = New RectangleF(ltzoneBounds.Left, ltzoneBounds.Top, ltzoneBounds.Width, ltzoneBounds.Height) ' This rectangle is in image (logical) coordinates with top-left view perspective ' Convert to the physical coordinates of the viewer zoneBounds = t.RectangleToPhysical(zoneBounds) ' Now draw this zone on the viewer surface If (ocrZone.Selected) Then e.Graphics.DrawRectangle(selectedPen, zoneBounds.X, zoneBounds.Y, zoneBounds.Width - 1, zoneBounds.Height - 1) Else e.Graphics.DrawRectangle(normalPen, zoneBounds.X, zoneBounds.Y, zoneBounds.Width - 1, zoneBounds.Height - 1) End If ' Draw the zone name on the left hand corner of the zone ' Note, in a real application you might want to have an option to show/hide the zone names (labels) Dim labelSize As SizeF = e.Graphics.MeasureString(ocrZone.Name, Font) Dim labelRectangle As New RectangleF(zoneBounds.X, zoneBounds.Y - labelSize.Height, labelSize.Width, labelSize.Height) e.Graphics.FillRectangle(Brushes.Yellow, labelRectangle) e.Graphics.DrawString(ocrZone.Name, Font, Brushes.Black, labelRectangle.X, labelRectangle.Y) Next End Using End If End Sub Public NotInheritable Class LEAD_VARS Public Const ImagesDir As String = "C:\Users\Public\Documents\LEADTOOLS Images" End Class
// Assume Form1 is a Windwos.Forms form in your application // The OCR engine we are using private IOcrEngine _ocrEngine; // The document we are using private IOcrDocument _ocrDocument; // Our raster image viewer instance private RasterImageViewer _viewer; public Form1() { InitializeComponent(); // Initialize the raster image viewer // Turn on use DPI, center the image, add border padding and frame shadow to show that our calculations will be // independent on all of those extra options _viewer = new RasterImageViewer(); _viewer.Dock = DockStyle.Fill; _viewer.BackColor = SystemColors.AppWorkspace; _viewer.UseDpi = true; _viewer.BorderPadding.All = 8; _viewer.FrameSize = new SizeF(1, 1); _viewer.FrameShadowSize = new SizeF(2, 2); _viewer.SizeMode = RasterPaintSizeMode.Normal; _viewer.HorizontalAlignMode = RasterPaintAlignMode.Center; _viewer.VerticalAlignMode = RasterPaintAlignMode.Center; _viewer.AutoDisposeImages = true; _viewer.InteractiveMode = RasterViewerInteractiveMode.None; // Turn on scale to gray painting in the viewer RasterPaintProperties props = _viewer.PaintProperties; props.PaintDisplayMode |= RasterPaintDisplayModeFlags.ScaleToGray; _viewer.PaintProperties = props; // Subscribe to the viewer events we need _viewer.KeyDown += new KeyEventHandler(_viewer_KeyDown); _viewer.MouseDown += new MouseEventHandler(_viewer_MouseDown); _viewer.PostImagePaint += new PaintEventHandler(_viewer_PostImagePaint); Controls.Add(_viewer); _viewer.BringToFront(); // Create and startup the OCR engine _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.Plus, false); _ocrEngine.Startup(null, null, null, null); // Create the OCR document _ocrDocument = _ocrEngine.DocumentManager.CreateDocument(); // Load an image into the OCR document string tifFileName = Path.Combine(LEAD_VARS.ImagesDir, "Ocr1.tif"); IOcrPage ocrPage = _ocrDocument.Pages.AddPage(tifFileName, null); // Do auto zone ocrPage.AutoZone(null); // AutoZone does not specify a name for the zones, so loop through all the zones and set their names // to a unique value. We will use the name in the paint code later IOcrZoneCollection ocrZones = ocrPage.Zones; for(int i = 0; i < ocrZones.Count; i++) { OcrZone ocrZone = ocrZones[i]; // Construct the name from the ID ocrZone.Name = string.Format("Zone {0}", ocrZone.Id); ocrZones[i] = ocrZone; } // Show the same image in the viewer _viewer.Image = ocrPage.GetRasterImage(); // Note, the image we got from GetRasterImage is a copy of the image in the engine // Since we set teh AutoDisposeImages of the viewer to "true", the image will be disposed // when the viewer is disposed at application termination Text = "+ to zoom in, - to zoom out, enter to return to 100%. Select the zones with the mouse"; } protected override void OnFormClosed(FormClosedEventArgs e) { // Dispose the document _ocrDocument.Dispose(); // Shutdown the OCR engine _ocrEngine.Shutdown(); _ocrEngine.Dispose(); base.OnFormClosed(e); } private void _viewer_KeyDown(object sender, KeyEventArgs e) { const double zoomRatio = 1.2; double scaleFactor = _viewer.ScaleFactor; switch(e.KeyCode) { case Keys.Add: case Keys.Oemplus: // Zoon in scaleFactor *= zoomRatio; e.Handled = true; break; case Keys.Subtract: case Keys.OemMinus: // Zone out scaleFactor /= zoomRatio; e.Handled = true; break; case Keys.Enter: scaleFactor = 1; e.Handled = true; break; } const double minimumScaleFactor = 0.05; const double maximumScaleFactor = 11; scaleFactor = Math.Max(minimumScaleFactor, Math.Min(maximumScaleFactor, scaleFactor)); // Check if scale factor has changed if(scaleFactor != _viewer.ScaleFactor) { _viewer.BeginUpdate(); // Yes, zoom keeping the center of the image // Get what you see in physical coordinates Rectangle rc = Rectangle.Intersect(_viewer.PhysicalViewRectangle, _viewer.ClientRectangle); // Get the center of what you see in physical coordinates PointF center = new PointF(rc.Left + rc.Width / 2, rc.Top + rc.Height / 2); Transformer t = new Transformer(_viewer.Transform); // Get the center of what you see in logical coordinates center = t.PointToLogical(center); _viewer.ScaleFactor = scaleFactor; // Bring the original center into the view center t = new Transformer(_viewer.Transform); // Get the center of what you saw before the zoom in physical coordinates center = t.PointToPhysical(center); // Bring the old center into the center of the view _viewer.CenterAtPoint(Point.Round(center)); _viewer.EndUpdate(); } } private void _viewer_MouseDown(object sender, MouseEventArgs e) { // Perform hit-testing on the zones if(_ocrEngine != null && _ocrEngine.IsStarted && _ocrDocument != null && _ocrDocument.Pages.Count > 0 && e.Button == MouseButtons.Left) { // Get the transform of the viewer // Use the transform that takes the DPI into consideration since we turned that on using(Matrix matrix = _viewer.GetTransformWithDpi()) { Transformer t = new Transformer(matrix); // Convert the mouse click coordinates from physical (viewer) to logical (image) PointF point = new PointF(e.X, e.Y); point = t.PointToLogical(point); // Hit test the zones // An alternitave to calling HitTestZone is to loop through all the zones // and get the value of .Bounds in pixels, then check if the point is inside // the boundaries. IOcrPage ocrPage = _ocrDocument.Pages[0]; LeadPoint lPoint = new LeadPoint((int)point.X, (int)point.Y); int zoneIndex = ocrPage.HitTestZone(new LogicalPoint(lPoint)); if(zoneIndex != -1) { // We hit a zone, loop through all the zones, unselect all but the hit tested zone for(int index = 0; index < ocrPage.Zones.Count; index++) { // Since OcrZone is a structure, we cannot simply do // ocrZone.Zones[index].Selected = value // We have to get a copy of the structure, modify it and set it back OcrZone ocrZone = ocrPage.Zones[index]; if(index != zoneIndex) ocrZone.Selected = false; else ocrZone.Selected = true; ocrPage.Zones[index] = ocrZone; } // Re-paint the viewer to show the new zones _viewer.Invalidate(); } } } } private void _viewer_PostImagePaint(object sender, PaintEventArgs e) { // Draw the zones on the viewer in their correct location if(_ocrEngine != null && _ocrEngine.IsStarted && _ocrDocument != null && _ocrDocument.Pages.Count > 0) { // Get the transform of the viewer // Use the transform that takes the DPI into consideration since we turned that on using(Matrix matrix = _viewer.GetTransformWithDpi()) { Transformer t = new Transformer(matrix); IOcrPage ocrPage = _ocrDocument.Pages[0]; Pen normalPen = new Pen(Color.Blue, 1); Pen selectedPen = new Pen(Color.Red, 2); selectedPen.DashStyle = DashStyle.Dash; foreach(OcrZone ocrZone in ocrPage.Zones) { // Get the zone bounds in pixels // You can also use ocrPage.GetZoneBoundsInPixels here LeadRect ltzoneBounds = ocrZone.Bounds.ToRectangle(ocrPage.DpiX, ocrPage.DpiY); RectangleF zoneBounds = new RectangleF(ltzoneBounds.Left, ltzoneBounds.Top, ltzoneBounds.Width, ltzoneBounds.Height); // This rectangle is in image (logical) coordinates with top-left view perspective // Convert to the physical coordinates of the viewer zoneBounds = t.RectangleToPhysical(zoneBounds); // Now draw this zone on the viewer surface if(ocrZone.Selected) e.Graphics.DrawRectangle(selectedPen, zoneBounds.X, zoneBounds.Y, zoneBounds.Width - 1, zoneBounds.Height - 1); else e.Graphics.DrawRectangle(normalPen, zoneBounds.X, zoneBounds.Y, zoneBounds.Width - 1, zoneBounds.Height - 1); // Draw the zone name on the left hand corner of the zone // Note, in a real application you might want to have an option to show/hide the zone names (labels) SizeF labelSize = e.Graphics.MeasureString(ocrZone.Name, Font); RectangleF labelRectangle = new RectangleF(zoneBounds.X, zoneBounds.Y - labelSize.Height, labelSize.Width, labelSize.Height); e.Graphics.FillRectangle(Brushes.Yellow, labelRectangle); e.Graphics.DrawString(ocrZone.Name, Font, Brushes.Black, labelRectangle.X, labelRectangle.Y); } } } } static class LEAD_VARS { public const string ImagesDir = @"C:\Users\Public\Documents\LEADTOOLS Images"; }
// Assume MainPage is a Windows.UI.Xaml.Controls.Page in your application // Assume this is your main page canvas private Canvas _canvas = null; // The OCR engine we are using private IOcrEngine _ocrEngine; // The document we are using private IOcrDocument _ocrDocument; // Our raster image viewer instance private RasterImageViewer _viewer = null; public MainPage() { InitializeComponent(); _viewer.ImageHorizontalAlignment = ControlAlignment.Center; _viewer.ImageVerticalAlignment = ControlAlignment.Center; _viewer.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 255, 255)); _viewer.AutoDisposeImages = true; // Subscribe to the viewer events we need _viewer.PointerPressed += _viewer_PointerPressed; _viewer.TransformChanged += _viewer_TransformChanged; _viewer.Loaded += _viewer_Loaded; _canvas.Children.Add(_viewer); } private async void _viewer_Loaded(object sender, RoutedEventArgs e) { // Create and startup the OCR engine _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.Advantage, false); _ocrEngine.Startup(null, null, String.Empty, Tools.OcrEnginePath); // Create the OCR document _ocrDocument = _ocrEngine.DocumentManager.CreateDocument(); // Load an image into the OCR document IOcrPage ocrPage = null; string tifFileName = @"Assets\Ocr1.tif"; using (RasterCodecs codecs = new RasterCodecs()) { StorageFile loadFile = await Tools.AppInstallFolder.GetFileAsync(tifFileName); using (RasterImage image = await codecs.LoadAsync(LeadStreamFactory.Create(loadFile))) ocrPage = _ocrDocument.Pages.AddPage(image, null); } // Do auto zone ocrPage.AutoZone(null); // AutoZone does not specify a name for the zones, so loop through all the zones and set their names // to a unique value. We will use the name in the paint code later IOcrZoneCollection ocrZones = ocrPage.Zones; for (int i = 0; i < ocrZones.Count; i++) { OcrZone ocrZone = ocrZones[i]; // Construct the name from the ID ocrZone.Name = string.Format("Zone {0}", ocrZone.Id); ocrZones[i] = ocrZone; } // Show the same image in the viewer _viewer.Image = ocrPage.GetRasterImage(); // Note, the image we got from GetRasterImage is a copy of the image in the engine // Since we set the AutoDisposeImages of the viewer to "true", the image will be disposed // when the viewer is disposed at application termination this.Name = "+ to zoom in, - to zoom out, enter to return to 100%. Select the zones with the mouse"; } protected override void OnNavigatedFrom(NavigationEventArgs e) { // Shutdown the OCR engine _ocrEngine.Shutdown(); base.OnNavigatedFrom(e); } private void _viewer_PointerPressed(object sender, PointerRoutedEventArgs e) { // Perform hit-testing on the zones if(_ocrEngine != null && _ocrEngine.IsStarted && _ocrDocument != null && _ocrDocument.Pages.Count > 0) { PointerPoint pp = e.GetCurrentPoint(_viewer); LeadPointD leadPointD = LeadPointDHelper.Create(pp.Position.X, pp.Position.Y); LeadMatrix matrix = new LeadMatrix(_viewer.Transform.M11, _viewer.Transform.M12, _viewer.Transform.M21, _viewer.Transform.M22, _viewer.Transform.OffsetX, _viewer.Transform.OffsetY); leadPointD = matrix.TransformPoint(leadPointD); // Hit test the zones // An alternitave to calling HitTestZone is to loop through all the zones // and get the value of .Bounds in pixels, then check if the point is inside // the boundaries. IOcrPage ocrPage = _ocrDocument.Pages[0]; LeadPoint lPoint = LeadPointHelper.Create((int)leadPointD.X, (int)leadPointD.Y); int zoneIndex = ocrPage.HitTestZone(lPoint); if(zoneIndex != -1) { // We hit a zone, loop through all the zones, unselect all but the hit tested zone for(int index = 0; index < ocrPage.Zones.Count; index++) { // Since OcrZone is a structure, we cannot simply do // ocrZone.Zones[index].Selected = value // We have to get a copy of the structure, modify it and set it back OcrZone ocrZone = ocrPage.Zones[index]; if(index != zoneIndex) ocrZone.Selected = false; else ocrZone.Selected = true; ocrPage.Zones[index] = ocrZone; } // Re-paint the viewer to show the new zones _viewer.Invalidate(); } } } void _viewer_TransformChanged(object sender, EventArgs e) { // Draw the zones on the viewer in their correct location if (_ocrEngine != null && _ocrEngine.IsStarted && _ocrDocument != null && _ocrDocument.Pages.Count > 0) { IOcrPage ocrPage = _ocrDocument.Pages[0]; foreach (OcrZone ocrZone in ocrPage.Zones) { // Get the zone bounds LeadRectD ltzoneBounds = new LeadRectD { X = ocrZone.Bounds.X, Y = ocrZone.Bounds.Y, Height = ocrZone.Bounds.Height, Width = ocrZone.Bounds.Width, }; LeadMatrix matrix = new LeadMatrix(_viewer.Transform.M11, _viewer.Transform.M12, _viewer.Transform.M21, _viewer.Transform.M22, _viewer.Transform.OffsetX, _viewer.Transform.OffsetY); ltzoneBounds = matrix.TransformRect(ltzoneBounds); SolidColorBrush normalBrush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 0, 0)); SolidColorBrush selectedBrush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 0, 0)); Rectangle rect = new Rectangle { Width = ltzoneBounds.Width, Height = ltzoneBounds.Height, Stroke = (ocrZone.Selected) ? selectedBrush : normalBrush, StrokeThickness = (ocrZone.Selected) ? 2 : 1 }; _canvas.Children.Add(rect); Canvas.SetLeft(rect, ltzoneBounds.X); Canvas.SetTop(rect, ltzoneBounds.Y); // Add the zone name TextBlock on the left hand corner of the zone // Note, in a real application you might want to have an option to show/hide the zone names (labels) TextBlock textBlock = new TextBlock(); textBlock.Name = ocrZone.Name; textBlock.InvalidateMeasure(); textBlock.RenderTransformOrigin = new Point(ltzoneBounds.X, ltzoneBounds.Y - textBlock.Height); } } }
Target Platforms: Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2