Tech Off Post

Single Post Permalink

View Thread: I always get a black backgraound with DrawingContext in WPF
  • User profile image
    Dioniz

    Whew! Thanks dex. Actually I wasn't going to do anything drastic.

     I put the background on first to give it the lowest Z order and then pass over it in the hit testing. Here is the complete code for the sake of public documentation; it draw some scary ghost:

    Imports System.Windows
    Imports System.Windows.Media
    Imports System.Collections.Generic
    Imports System.Windows.Input
    
    Namespace WindowHostingVisual
       Class Application
          <STAThread()> _
          Public Shared Sub Main()
             Dim whv As New WindowHostingVisual.WindowHostingVisual()
             whv.ShowDialog()
          End Sub
       End Class
    
       Namespace WindowHostingVisual
          Public Class WindowHostingVisual
             Inherits Window
    
             Private visuals As New List(Of Visual)()
    
             Public Sub New()
                Title = "Hosting DrawingVisuals"
                Width = 400
                Height = 400
                Background = Brushes.Aquamarine
                Me.WindowStartupLocation = Windows.WindowStartupLocation.CenterScreen
    
                Dim bodyVisual As New DrawingVisual()
                Dim eyesVisual As New DrawingVisual()
                Dim mouthVisual As New DrawingVisual()
                Dim visBackground As New DrawingVisual
    
                Using dc As DrawingContext = bodyVisual.RenderOpen()
                   dc.DrawGeometry(Brushes.Blue, Nothing, Geometry.Parse("M 240,250 C 200,375 200,250 175,200 C 100,400 100,250 100,200 C 0,350 0,250 30,130 C 75,0 100,0 150,0 C 200,0 250,0 250,150 Z"))
                End Using
    
                Using dc As DrawingContext = eyesVisual.RenderOpen()
                   dc.DrawEllipse(Brushes.Black, New Pen(Brushes.White, 10), New Point(95, 95), 15, 15)
                   dc.DrawEllipse(Brushes.Black, New Pen(Brushes.White, 10), New Point(170, 105), 15, 15)
                End Using
    
                Using dc As DrawingContext = mouthVisual.RenderOpen()
                   Dim p As New Pen(Brushes.Black, 10)
                   p.StartLineCap = PenLineCap.Round
                   p.EndLineCap = PenLineCap.Round
                   dc.DrawLine(p, New Point(75, 160), New Point(175, 150))
                End Using
    
                Using dc As DrawingContext = visBackground.RenderOpen
                   dc.DrawRectangle(Background, Nothing, New Rect(0, 0, Width, Height))
                End Using
    
                visuals.Add(visBackground)
                visuals.Add(bodyVisual)
                visuals.Add(eyesVisual)
                visuals.Add(mouthVisual)
    
                ' Bookkeeping:
                For Each v As Visual In visuals
                   AddVisualChild(v)
                   AddLogicalChild(v)
                Next
    
             End Sub
    
             ' The two necessary overrides, implemented for the single Visual:
             Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
                Get
                   Return visuals.Count
                End Get
             End Property
    
             Protected Overrides Function GetVisualChild(index As Integer) As Visual
                If index < 0 OrElse index >= visuals.Count Then
                   Throw New ArgumentOutOfRangeException("index")
                End If
                Return visuals(index)
             End Function
    
             Protected Overrides Sub OnMouseLeftButtonDown(e As MouseButtonEventArgs)
                ' Rotate object clicked on.
    
                MyBase.OnMouseLeftButtonDown(e)
                ' Retrieve the mouse pointer location relative to the Window
                Dim location As Point = e.GetPosition(Me)
                ' Perform visual hit testing
                Dim result As HitTestResult = VisualTreeHelper.HitTest(Me, location)
                ' If we hit any DrawingVisual, rotate it
                If result.VisualHit.[GetType]() = GetType(DrawingVisual) Then
                   Dim dv As DrawingVisual = TryCast(result.VisualHit, DrawingVisual)
                   ' Don't rotate background.
                   If dv.Equals(visuals.Item(0)) Then
                      Exit Sub
                   End If
                   If dv.Transform Is Nothing Then
                      dv.Transform = New RotateTransform()
                   End If
                   TryCast(dv.Transform, RotateTransform).Angle += 1
                End If
             End Sub
          End Class
       End Namespace
    End Namespace
    

    I think my real question is what I am really drawing on. It seems to not be the window object. I don't know what the DrawingContext actually is and where it fits in. I do now know the drawn objects can be accessed through LogicalTreeHelper and VisualTreeHelper. To quote from WPF Unleashed: "However, you can easily traverse both the logical and visual trees using the somewhat
    symmetrical System.Windows.LogicalTreeHelper and System.Windows.Media.
    VisualTreeHelper classes."