0

I am writing an app in C#4.0/WPF that displays a piece of machinery in an image control within a canvas. The user drags coloured text blocks on to the image to indicate an area of wear or damage (I have written code that creates and moves a new text block as a user drags it). Once the user has completed dragging the text blocks on the canvas my aim is to capture background and text blocks in a bitmap to be sent to a report. The trouble is that when I try and do this the image that is captured shows only the text blocks that have been dragged and not the background. I have created a test project with what looks like exactly the same code to me and it captures the canvas with all contents perfectly. I have not included the code that performs the text block dragging in the test project as I dont think it is relevant, however I have included it here for clarity. I have included the relevant code from both the main and test app. I have also included images produced in both the main and test apps. I am not too hot on XAML so I suspect this is where the fault lies. I have tried to post images from both test and main apps but the site will not allow as I have less than 10 rep points! I can of course do this once I have the points.I have not included all XAML for the form as it is a big form and there is a lot of code - I can do this if required though.I have researched high and low and have posted this on other forums with no luck. Hope some one can help! Many Thanks, Jeff and apologies for the long posting!

Test App XAML:

<Canvas Name="canvBlade1Image" Margin="33,23,719,6">
<TextBlock Height="15" Name="tblkRed" Width="18" FontSize="11" Background="Red"         Canvas.Left="200" Canvas.Top="444" HorizontalAlignment="Center" TextAlignment="Center" />
<TextBlock Background="Orange" FontSize="11" Height="15" Name="tblkOrange" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="465" />
<TextBlock Background="Yellow" FontSize="11" Height="15" Name="tblkYellow" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="486" />
<TextBlock Background="Lime" FontSize="11" Height="15" Name="tblkGreen" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="508" />
<TextBlock Background="DodgerBlue" FontSize="11" Height="15" Name="tblkGre" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="528" />
        <Canvas.Background>
              <ImageBrush ImageSource="C:\Users\jeff\documents\blankblade.png" Stretch="Fill"></ImageBrush>
        </Canvas.Background>

test app C#

private void btnRendertoBitmap_Click(object sender, RoutedEventArgs e)
{
 Transform transform = canvBlade1Image.LayoutTransform;
 canvBlade1Image.LayoutTransform = null;
 Size size = new Size(canvBlade1Image.ActualWidth, canvBlade1Image.ActualHeight);
 canvBlade1Image.Measure(size);
 canvBlade1Image.Arrange(new Rect(size));
 RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d, PixelFormats.Pbgra32);
 renderBitmap.Render(canvBlade1Image);
 using (FileStream outStream = new FileStream(@"C:\Users\jeff\documents\blade.png.", FileMode.Create))
 {
       PngBitmapEncoder encoder = new PngBitmapEncoder();
       encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
       encoder.Save(outStream);
 }

}

![test app output][1]

Main app XAML

<Canvas Name="canvBlade1Image" Margin="33,23,719,6">
<TextBlock Height="15" Name="tblkRed" Width="18" FontSize="11" Background="Red"           Canvas.Left="200" Canvas.Top="444" HorizontalAlignment="Center" TextAlignment="Center" />
<TextBlock Background="Orange" FontSize="11" Height="15" Name="tblkOrange" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="465" />
<TextBlock Background="Yellow" FontSize="11" Height="15" Name="tblkYellow" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="486" />
<TextBlock Background="Lime" FontSize="11" Height="15" Name="tblkGreen" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="508" />
<TextBlock Background="DodgerBlue" FontSize="11" Height="15" Name="tblkGre" TextAlignment="Center" Width="18" Canvas.Left="200" Canvas.Top="528" />
<Canvas.Background>
    <ImageBrush ImageSource="C:\Users\jeff\documents\blankblade.png" Stretch="Fill"></ImageBrush>
</Canvas.Background>

Main App C#

public bool ExportToPNG()
{
  try
  {
  Transform transform = canvBlade1Image.LayoutTransform;
  canvBlade1Image.LayoutTransform = null;
  Size size = new Size(canvBlade1Image.ActualWidth, canvBlade1Image.ActualHeight);
  canvBlade1Image.Measure(size);
  canvBlade1Image.Arrange(new Rect(size));
  RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d, PixelFormats.Pbgra32);
  renderBitmap.Render(canvBlade1Image);
  using (FileStream outStream = new FileStream(@"C:\Users\jeff\documents\blade.png.", FileMode.Create))
  {
      PngBitmapEncoder encoder = new PngBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
      encoder.Save(outStream);
  }
  return true;
  }
  catch (Exception E)
  {
  MessageBox.Show("Error converting blade image" + E);
  return false;
  }
}

![Main app output][2]

Code to drag textblocks

 private void canvBlade1Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {                 
        if(doNotAllowNewFault == true && (((System.Windows.Controls.TextBlock)(e.Source)).Text   == "")) 
        {
            return;
        }   
        if (e.Source != canvBlade1Image && e.Source.GetType() == typeof(System.Windows.Controls.TextBlock))
        {
            overlayTextBlockBackgroundBrush = ((System.Windows.Controls.TextBlock)(e.Source)).Background;
            overlayTextBlockTextAlignment = TextAlignment.Center;
            overlayTextBlockFontSize = ((System.Windows.Controls.TextBlock)(e.Source)).FontSize;
            overlayTextBlockText = ((System.Windows.Controls.TextBlock)(e.Source)).Text;
            canvBlade1Image.Children.Remove(sourceTextBlock);
            if(((System.Windows.Controls.TextBlock)(e.Source)).Text !="")
            {
                moveFault = true;
            }
            sourceElementLeft = Canvas.GetLeft((TextBlock)e.Source);
            sourceElementTop = Canvas.GetLeft((TextBlock)e.Source);
            canvBlade1Image.Children.Remove(sourceTextBlock);
            sourceTextBlock = (TextBlock)e.Source;
            mIsDown = true;
            mStartPoint = e.GetPosition(canvBlade1Image);
            e.Handled = true;
        }
    }


private void canvBlade1Image_MouseMove(object sender, MouseEventArgs e)
{
Double actualX = Math.Abs(e.GetPosition(canvBlade1Image).X);
Double startX = mStartPoint.X;
Double actualY = Math.Abs(e.GetPosition(canvBlade1Image).Y);
Double startY = mStartPoint.Y;

if (mIsDown)
{
    if (!mIsDragging)
    {
        DragStarted();
    }
}

if (mIsDragging)
{
    DragMoved();
}
e.Handled = true;
}


private void DragStarted()
{
mIsDragging = true;
sourceElementLeft = Canvas.GetLeft(sourceTextBlock);
sourceElementTop = Canvas.GetTop(sourceTextBlock);
overlayTextBlock = new TextBlock();
overlayTextBlock.Background = sourceTextBlock.Background;
overlayTextBlock.Width = sourceTextBlock.RenderSize.Width;
overlayTextBlock.Height = sourceTextBlock.RenderSize.Height;
if (moveFault == false)
{
      overlayTextBlock.Text = blade1FaultNumber.ToString();
}
else
{
      overlayTextBlock.Text =overlayTextBlockText;
}
overlayTextBlock.FontSize = overlayTextBlockFontSize;
overlayTextBlock.TextAlignment = overlayTextBlockTextAlignment;
canvBlade1Image.Children.Add(overlayTextBlock);
overlayTextBlock.Opacity = 1;
}

private void DragMoved()
{
Point currentPosition = Mouse.GetPosition(canvBlade1Image);
double elementLeft = (currentPosition.X - mStartPoint.X) + sourceElementLeft;
double elementTop = (currentPosition.Y - mStartPoint.Y) + sourceElementTop;
Canvas.SetLeft(overlayTextBlock, elementLeft);
Canvas.SetTop(overlayTextBlock, elementTop);
}

private void canvBlade1Image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (mIsDown)
{
    DragFinished(false);
    e.Handled = true;
}
}

private void DragFinished(Boolean cancelled)
{


if (mIsDragging)
{
      if( moveFault)
      {
                canvBlade1Image.Children.Remove(sourceTextBlock);
      }
      else
      {
            Canvas.SetLeft(sourceTextBlock, Canvas.GetLeft(overlayTextBlock));
            Canvas.SetTop(sourceTextBlock, Canvas.GetTop(overlayTextBlock));
            TextBlock replacementTextBlock = new TextBlock();
            Canvas.SetLeft(replacementTextBlock, sourceElementLeft);
            Canvas.SetTop(replacementTextBlock, sourceElementTop);
            replacementTextBlock.Height = overlayTextBlock.Height;
            replacementTextBlock.Width = overlayTextBlock.Width;
            replacementTextBlock.Opacity = 1;
            replacementTextBlock.FontSize = 11;
            replacementTextBlock.Background = overlayTextBlock.Background;
            blade1FaultNumber++;
            canvBlade1Image.Children.Add(replacementTextBlock);
      }
          moveFault = false;
          overlayTextBlock = null;
          mIsDragging = false;
          mIsDown = false;
          txtFaultBriefDesciption1.IsEnabled = true;
          txtFaultdetails1.IsEnabled = true;
          cboMeters1.IsEnabled = true;

}
}
JeffG
  • 5
  • 2
  • 7
  • Two questions. In `btnRendertoBitmap_Click` (in the first code block) there is something called `canv1`. Where is that in XAML? In the same method you write the encoded bitmap to `blankblade.png`, which at the same time is the source bitmap of the ImageBrush. Is that intended? – Clemens Jan 24 '13 at 13:10
  • What if you tried just adding the background as an image? – jle Jan 24 '13 at 13:24
  • @Clemens well spotted - that wasn't intended. I had made a couple of typos trying to hide sensitive info. I've now corrected these; in both cases canvBlade1Image is the name of the canvas, blankblade.png is the background and blade.png is the output file. – JeffG Jan 24 '13 at 16:13
  • @jle Not sure what you mean. I have tried adding the background image to the canvas directly in XAML as above. I've also tried it in C# by assigning the image to an ImageBrush then used that as the canvas background. The results are the same - it works in the test app but not in my prod app. – JeffG Jan 24 '13 at 16:19

2 Answers2

0

How about you add this to your canvas and get rid of the background?:

Canvas Name="canvBlade1Image" Margin="33,23,719,6">

...other stuff on canvas
Image Source="C:\Users\jeff\documents\blankblade.png"/>

/Canvas>

Community
  • 1
  • 1
jle
  • 9,316
  • 5
  • 48
  • 67
  • Thanks but that won't work I'm afraid. The canvas object does not itself contain an image source property. The image source needs to be assigned to the background property of the canvas. The background is of type brush so the brush needs to be initialized with the image and then assigned to the background. – JeffG Jan 25 '13 at 14:41
0

After much frustration I have now been able to resolve this issue. I was unable to find out why the background was not rendering in my prod app with exactly the same code as my successful test app. I therefore tried a new route of explicitly rendering the background. This worked, code below:

       try
          {
              RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
              (int)canvBlade1Image.ActualWidth,(int)canvBlade1Image.ActualHeight,96d,
              96d, PixelFormats.Pbgra32);

              DrawingVisual drawingVisual = new DrawingVisual();
              using (DrawingContext drawingContext = drawingVisual.RenderOpen())
                  drawingContext.DrawRectangle(canvBlade1Image.Background, null, new Rect(0, 0, canvBlade1Image.ActualWidth, canvBlade1Image.ActualHeight));
              renderBitmap.Render(drawingVisual);
              renderBitmap.Render(canvBlade1Image);

              using (FileStream outStream = new FileStream(@"C:\Images\Keep\img1.png.", FileMode.Create))
              {
                  PngBitmapEncoder encoder = new PngBitmapEncoder();
                  encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
                  encoder.Save(outStream);
              }
          }
JeffG
  • 5
  • 2
  • 7