2011-12-18 55 views
0

一張圖片勝過千言萬語 - 所以這裏是現有的對理想的:如何在運行時繪製一條從文本框中間退出的線?

enter image description here

這是我試過的w/o成功:

public MainWindow() 
    { 
     InitializeComponent(); 
     TextBlock txt = new TextBlock(); 
     txt.Text = "asdsahd sakh uj"; 
     txt.Background = Brushes.LightBlue; 
     Canvas.SetLeft(txt, 100); 
     container.Children.Add(txt); 


     Line line = new Line(); 
     line.SetBinding(Line.X1Property, new Binding("Canvas.Left") {ElementName = "txt"}); 
     line.X2 = line.X1; 
     line.Y1 = 0; 
     line.Y2 = 100; 
     line.StrokeThickness = 2; 
     container.Children.Add(line); 
    } 
+0

我不確定設置TxtBlock txt - 新的TextBlock()是否給它一個ElementName。看起來像明確地設置ElementName。 – Paparazzi 2011-12-18 15:49:46

+0

謝謝BalamBalam,試了一下,沒有幫助。 – Erez 2011-12-18 16:05:25

回答

0

在解決方案在下面,我假設你的Canvas的高度和寬度可以在運行時改變,並且你的TextBlock也可以具有動態改變的高度和寬度。該方法看起來很複雜,但不是。當然,在XAML中這樣做會更加可讀:

  1. 創建一個TextBlock添加到畫布。
  2. 創建一個Line添加到畫布。
  3. 使用MultiBinding來計算TextBlockCanvas.Left屬性。如果CanvasTextBlock的寬度發生變化,則此綁定將重新評估,並且IMultiValueConverter將提供新值。 TextBlock的值Canvas.Left應該是:Canvas.ActualWidth/2-TextBlock.ActualWidth/2
  4. 要與步驟3中相同,但是這次是Line
  5. 使用MultiBinding來計算LineLine.Y2屬性。假設您想將線畫到Canvas的底部邊緣。要計算這個:Canvas.ActualHeight - TextBlock.ActualHeight。如果更改和IMultiValueConverter將提供新值,綁定將重新評估。
  6. 使用BindingLine上設置Canvas.Top屬性。在此示例中,Line緊靠TextBlock之下,因此我們可以將其綁定到TextBlock.ActualHeight

的TextBlock和線製作

public MainWindow() 
    { 
     InitializeComponent(); 

     // Create TextBlock and Line 
     var textBlock = new TextBlock {Text = "123456"}; 
     var line = new Line { StrokeThickness = 2, Stroke = new SolidColorBrush { Color = Colors.Black }, Y1 = 0 }; 
     myCanvas.Children.Add(textBlock); 
     myCanvas.Children.Add(line); 

     // Setup bindings 
     InitializeTextBlockCanvasLeftBinding(myCanvas, textBlock); 
     InitializeLineCanvasLeftBinding(myCanvas, line); 
     InitializeLineY2Binding(myCanvas, textBlock, line); 
     InitializeLineCanvasTopBinding(myCanvas, textBlock, line); 
    } 

    private void InitializeLineCanvasTopBinding(Canvas canvas, TextBlock textBlock, Line line) 
    { 
     var textBlockActualHeightBinding = new Binding 
     { 
      Source = textBlock, 
      Path = new PropertyPath("ActualHeight"), 
     }; 

     BindingOperations.SetBinding(line, Canvas.TopProperty, textBlockActualHeightBinding); 
    } 

    private void InitializeLineY2Binding(Canvas canvas, TextBlock textBlock, Line line) 
    { 
     var canvasActualHeightBinding = new Binding 
     { 
      Source = myCanvas, 
      Path = new PropertyPath("ActualHeight"), 
     }; 

     var textBlockActualHeightBinding = new Binding 
     { 
      Source = textBlock, 
      Path = new PropertyPath("ActualHeight"), 
     }; 

     var lineY2MultiBinding = new MultiBinding { Converter = new LineY1MultiConverter() }; 
     lineY2MultiBinding.Bindings.Add(textBlockActualHeightBinding); 
     lineY2MultiBinding.Bindings.Add(canvasActualHeightBinding); 

     BindingOperations.SetBinding(line, Line.Y2Property, lineY2MultiBinding); 
    } 

    private void InitializeLineCanvasLeftBinding(Canvas canvas, Line line) 
    { 
     var lineActualWidthBinding = new Binding 
     { 
      Source = line, 
      Path = new PropertyPath("ActualWidth"), 
     }; 

     var canvasActualWidthBinding = new Binding 
     { 
      Source = myCanvas, 
      Path = new PropertyPath("ActualWidth"), 
     }; 

     var lineLeftMultiBinding = new MultiBinding { Converter = new CanvasLeftCenterMultiConverter() }; 
     lineLeftMultiBinding.Bindings.Add(lineActualWidthBinding); 
     lineLeftMultiBinding.Bindings.Add(canvasActualWidthBinding); 

     BindingOperations.SetBinding(line, Canvas.LeftProperty, lineLeftMultiBinding); 
    } 

    private void InitializeTextBlockCanvasLeftBinding(Canvas canvas, TextBlock textBlock) 
    { 
     var textBlockActualWidthBinding = new Binding 
     { 
      Source = textBlock, 
      Path = new PropertyPath("ActualWidth"), 
     }; 

     var canvasActualWidthBinding = new Binding 
     { 
      Source = myCanvas, 
      Path = new PropertyPath("ActualWidth"), 
     }; 

     var textBlockLeftMultiBinding = new MultiBinding { Converter = new CanvasLeftCenterMultiConverter() }; 
     textBlockLeftMultiBinding.Bindings.Add(textBlockActualWidthBinding); 
     textBlockLeftMultiBinding.Bindings.Add(canvasActualWidthBinding); 

     BindingOperations.SetBinding(textBlock, Canvas.LeftProperty, textBlockLeftMultiBinding); 
    } 

多轉換計算行

public class LineY1MultiConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values != null && values.Length == 2 && values[0] is double && values[1] is double) 
     { 
      var canvasHeight = (double)values[1]; 
      var textBlockHeight = (double) values[0]; 
      return canvasHeight - textBlockHeight; 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

多轉換的長度以在畫布上水平居中元件

public class CanvasLeftCenterMultiConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values != null && values.Length == 2 && values[0] is double && values[1] is double) 
     { 
      var canvasMiddle = (double)values[1]/2; 
      var elementHalf = (double) values[0]/2; 
      return canvasMiddle - elementHalf; 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

編輯

爲了使上面的代碼更加清晰 - 它真的只是一個1:1的翻譯以下XAML(使用MultiValueConverters從上面):

<Canvas x:Name="myCanvas" Background="Pink"> 
     <TextBlock x:Name="myTextBlock" Text="1234567890"> 
      <Canvas.Left> 
       <MultiBinding Converter="{l:CanvasLeftCenterMultiConverter}"> 
        <Binding RelativeSource="{RelativeSource Mode=Self}" Path="ActualWidth" /> 
        <Binding ElementName="myCanvas" Path="ActualWidth" /> 
       </MultiBinding> 
      </Canvas.Left> 
     </TextBlock> 
     <Line StrokeThickness="2" Stroke="Black" Canvas.Top="{Binding ElementName=myTextBlock, Path=ActualHeight}" Y1="0"> 
      <Line.Y2> 
       <MultiBinding Converter="{l:LineY1MultiConverter}"> 
        <Binding ElementName="myTextBlock" Path="ActualHeight" /> 
        <Binding ElementName="myCanvas" Path="ActualHeight" /> 
       </MultiBinding> 
      </Line.Y2> 
      <Canvas.Left> 
       <MultiBinding Converter="{l:CanvasLeftCenterMultiConverter}"> 
        <Binding RelativeSource="{RelativeSource Mode=Self}" Path="ActualWidth" /> 
        <Binding ElementName="myCanvas" Path="ActualWidth" /> 
       </MultiBinding> 
      </Canvas.Left> 
     </Line> 
    </Canvas> 

正如您所看到的 - 如果畫布大小發生變化,文字大小發生變化或線條粗細發生變化,則綁定將確保計算出Canvas.LeftCanvas.Top的新值。

希望這會有所幫助!

+0

它很長,所以我還沒有嘗試過,但我想這已經夠了,甚至更多......謝謝 – Erez 2011-12-18 21:42:11