2013-04-27 3 views
1

У меня есть холст сортов, полученных из «панели», используемый для пользовательского рисования линий и других геометрий, все из кода VB. Я получил этот подход из книги, и я не уверен, что это лучший подход. Часть чертежа работает до сих пор для меня.WPF: случайное размещение текстового поля на холсте

Но мне нужно, чтобы элемент управления текстовыми полями содержал текст, который может быть отредактирован пользователем. Текстовое поле должно быть размещено в координатах, определяемых динамически, а затем удалено. Вероятно, будут и другие элементы управления.

Следующий код ничего не делает:

tb = New TextBox() 
    tb.Text = "How now brown cow?" 
    tb.BorderThickness = New Thickness(3) 
    tb.BorderBrush = Brushes.CadetBlue 
    drawingSurface.Children.Add(tb) 

Это определение моих DrawingCanvas:

Public Class DrawingCanvas 
    Inherits Panel 

    Private visuals As New List(Of Visual)() 
    Private hits As New List(Of DrawingVisual)() 

    Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual 
     Return visuals(index) 
    End Function 
    Protected Overrides ReadOnly Property VisualChildrenCount() As Integer 
     Get 
     Return visuals.Count 
     End Get 
    End Property 

    Public Sub AddVisual(ByVal visual As Visual) 
     visuals.Add(visual) 
     MyBase.AddVisualChild(visual) 
     MyBase.AddLogicalChild(visual) 
    End Sub 

    Public Sub DeleteVisual(ByVal visual As Visual) 
     visuals.Remove(visual) 
     MyBase.RemoveVisualChild(visual) 
     MyBase.RemoveLogicalChild(visual) 
    End Sub 

    Public Function GetVisual(ByVal point As Point) As DrawingVisual 
     Dim hitResult As HitTestResult = VisualTreeHelper.HitTest(Me, point) 
     Return TryCast(hitResult.VisualHit, DrawingVisual) 
    End Function 

    Public Function GetVisuals(ByVal region As Geometry) As List(Of DrawingVisual) 
     hits.Clear() 
     Dim parameters As New GeometryHitTestParameters(region) 
     Dim callback As New HitTestResultCallback(AddressOf Me.HitTestCallback) 
     VisualTreeHelper.HitTest(Me, Nothing, callback, parameters) 
     Return hits 
    End Function 

    Private Function HitTestCallback(ByVal result As HitTestResult) As HitTestResultBehavior 
     Dim geometryResult As GeometryHitTestResult = CType(result, GeometryHitTestResult) 
     Dim visual As DrawingVisual = TryCast(result.VisualHit, DrawingVisual) 
     If visual IsNot Nothing AndAlso geometryResult.IntersectionDetail = IntersectionDetail.FullyInside Then 
      hits.Add(visual) 
      MsgBox("Ouch") 
     End If 
     Return HitTestResultBehavior.Continue 
    End Function 
End Class 

Вот XAML. Я добавил текстовое поле DrawingCanvas, чтобы увидеть, что-то появилось. Ничего. На самом деле, я хочу сделать это в коде, а не в XAML. Я думал, что могу спрятаться или переместить его динамически.

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:Music" 
    Title="MainWindow" Height="539" Width="892"> 
    <DockPanel> 
     <Menu DockPanel.Dock="Top" Name="MainMenu" VerticalAlignment="Top" Height="25"> 
      <MenuItem Name="File" Header="File"> 
       <MenuItem Name="Open" Header="Bla bla..."/> 
      </MenuItem> 
     </Menu> 
     <local:DrawingCanvas DockPanel.Dock="Bottom" x:Name="drawingSurface" RenderTransformOrigin="0.5,0.5" > 
      <TextBox Height="0" Name="TextBox1" Width="45" Text="How now brown cow?" /> 
     </local:DrawingCanvas> 
    </DockPanel> 
</Window> 

Спасибо, что помогли nooby. Решение было бы очень полезно для меня. Это было легко с формами окон, но мне нужна скорость рисования WPF.

ответ

0

Я думаю, вы немного здесь. В WPF у вас есть элемент управления Canvas. Я предлагаю вам использовать это вместо вашего собственного «DrawingCanvas», который я не могу получить для работы кстати. :((По какой-то причине я не могу создать блоки кода, так что если кто-то может изменить его, я был бы рад)

Во всяком случае,

<local:DrawingCanvas DockPanel.Dock="Bottom" x:Name="drawingSurface" RenderTransformOrigin="0.5,0.5" > 
    <TextBox Height="0" Name="TextBox1" Width="45" Text="How now brown cow?" /> 
</local:DrawingCanvas> 

Превращается:

<Canvas x:Name="drawingSurface"> 

</Canvas> 

А потом добавить текстовое поле просто сделать как ваш текущий код:.

Dim tb as New TextBox 
drawingSurface.Children.Add(tb) 

Это должно дать вам то, что вам нужно

Ей код для добавления прямоугольника на ваш холст.

Private Sub DrawBackground() 
    Dim Rect As New Rectangle() 
    Rect.Height = 50 
    Rect.Width = 50 
    Rect.Fill = Brushes.Cornsilk 
    drawingSurface.SetTop(Rect, 30) 
    drawingSurface.SetLeft(Rect, 100) 
    drawingSurface.Children.Add(Rect) 
End Sub 
+0

Я не показывал код, который использует DrawingCanvas. \t частного Суб DrawBackground() \t \t С помощью постоянного тока как DrawingContext = visBackground.RenderOpen() \t \t \t Dim кисти, как кисть = Brushes.Cornsilk \t \t \t Dim drawingPen Поскольку Pen = New Pen (Brushes.Cornsilk, 1) \t \t \t dc.DrawRectangle (щетка, drawingPen, New Rect (0, 0, dblScreenWidth, dblScreenHeight)) \t \t End Using \t \t drawingSurface.AddVisual (visBackground) \t End Sub – jokestacker

+0

Не совсем уверен, что вы после. Но я добавил код, который показывает, как добавить материал на ваш холст. – WozzeC

0

Я добавлю еще один ответ, который может быть больше в строке того, что вы ищете. Это класс, который наследует Canvas, который позволит вам нарисовать материал так же, как вы говорите в своем комментарии.

Я также создаю текстовое поле в случайном месте, когда оно создано.

Public Class DrawingCanvas 
    Inherits Canvas 
    Public RandomTextBox As New TextBox 
    Protected Overrides Sub OnRender(dc As System.Windows.Media.DrawingContext) 
     Dim brush As Brush = Brushes.Black 
     Dim drawingPen As Pen = New Pen(Brushes.Green, 3) 
     dc.DrawRectangle(brush, drawingPen, New Rect(5, 5, Me.ActualWidth - 5, Me.ActualHeight - 5)) 
     RandomTextBox.Text = "Herpdiderp" 
     If Not Me.Children.Contains(RandomTextBox) Then 
      Dim r As New Random() 
      RandomTextBox.Height = 23 
      RandomTextBox.Width = 100 
      Me.SetTop(RandomTextBox, r.Next(0, Me.ActualHeight - RandomTextBox.Height)) 
      Me.SetLeft(RandomTextBox, r.Next(0, Me.ActualWidth - RandomTextBox.Width)) 
      Me.Children.Add(RandomTextBox) 
     End If 
    End Sub 
End Class 
+0

Прошу прощения за отказ. Был занят другими вещами и путешествиями. Может быть, немного рано начинать задавать такие вопросы. Мне все еще нравится оригинальный Воццек на этом этапе. – jokestacker

+0

(Хорошо, что я не парикмахер.) Использование Canvas в качестве базового класса отлично работает. Мне пришлось заменить «Me» на «Canvas», что не имеет для меня никакого смысла: «Me» - это реальный экземпляр, а «Canvas» - это просто класс. Но отладчик сказал мне, что я обратился к «совместно используемому члену через экземпляр» и что я меняю его на Canvas. – jokestacker

+0

И «Canvas.SetLeft (RandomTextBox, r.Next (0, Me.ActualWidth - RandomTextBox.Width))« просто провоцирует мой мозг ООП. Почему не RandomTextBox.SetLeft (...) или .Left = n? Во всяком случае, я не видел ни одного Herpdiderp. Я играл с ним и прекратил рисовать что-нибудь еще, но ничего не работает. Я проверил, что текстовое поле находится в Me.Children и что оно имеет правильные значения. Он просто не рисует. – jokestacker

0

Это не полный ответ. #WozzeC, вы были правы в использовании холста - почти.

Мне удалось решить это только в xaml - я хочу, в конечном счете, решить его в vb.net.

<Window x:Class="MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <DockPanel HorizontalAlignment="Stretch" Name="DockPanel1" VerticalAlignment="Stretch" > 
     <Menu Height="23" DockPanel.Dock="Top" Name="Menu1" VerticalAlignment="Top" /> 
     <Canvas Name="Canvas1" Background="Aquamarine"> 
      <TextBox Canvas.Left="118" HorizontalScrollBarVisibility="Disabled" Canvas.Top="81" AcceptsReturn="True" Height="auto" Name="TextBox1" Width="68" Text="Herpdiderp" BorderThickness="0" Background="Aquamarine" /> 
     </Canvas> 
    </DockPanel> 
</Grid> 

А вот кусок кода, который расширяет текст по мере необходимости. Я думаю, что это почти здорово. Он расширяется как справа, так и вниз, как будто вы набираете форму.Он добавляет немного слишком много справа, но это не видно в этой версии, потому что цвет фона тот же.

Вот код события, который расширяет его право.

Imports System.Globalization 
Class MainWindow 
Private Sub TextBox1_TextChanged(sender As System.Object, e As System.Windows.Controls.TextChangedEventArgs) Handles TextBox1.TextChanged 
    Dim ft As New FormattedText(TextBox1.Text, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, New Typeface("Verdana"), 16, Brushes.Black) 
    TextBox1.Width = ft.Width 
End Sub 
End Class 

Я попытался это с моим существующим решением и текстовое поле делает не появляются. Я сделал DrawingCanvas в простой Canvas и закомментировал весь код, относящийся к DrawingCanvas. Появляется текстовое поле . Проблема заключается в следующем: мне нужна функциональность в DrawingCanvas, которая происходит из Canvas. Но поскольку методы базового класса защищены, я не могу добраться до них. Я могу использовать их только в производном классе, если нет другого способа, о котором я не знаю.

Любые идеи о том, как это решить?

+0

Это должно было закончиться. Я хотел показать новый код. – jokestacker