在解決方案在下面,我假設你的Canvas
的高度和寬度可以在運行時改變,並且你的TextBlock
也可以具有動態改變的高度和寬度。該方法看起來很複雜,但不是。當然,在XAML中這樣做會更加可讀:
- 創建一個
TextBlock
添加到畫布。
- 創建一個
Line
添加到畫布。
- 使用
MultiBinding
來計算TextBlock
的Canvas.Left
屬性。如果Canvas
或TextBlock
的寬度發生變化,則此綁定將重新評估,並且IMultiValueConverter
將提供新值。 TextBlock
的值Canvas.Left
應該是:Canvas.ActualWidth/2
-TextBlock.ActualWidth/2
。
- 要與步驟3中相同,但是這次是
Line
。
- 使用
MultiBinding
來計算Line
的Line.Y2
屬性。假設您想將線畫到Canvas
的底部邊緣。要計算這個:Canvas.ActualHeight
- TextBlock.ActualHeight
。如果更改和IMultiValueConverter
將提供新值,綁定將重新評估。
- 使用
Binding
在Line
上設置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.Left
和Canvas.Top
的新值。
希望這會有所幫助!
我不確定設置TxtBlock txt - 新的TextBlock()是否給它一個ElementName。看起來像明確地設置ElementName。 – Paparazzi 2011-12-18 15:49:46
謝謝BalamBalam,試了一下,沒有幫助。 – Erez 2011-12-18 16:05:25