對於TextBlock我們有時候需要豎直排列它的文字內容。
設定TextBlock的顯示內容有兩種方式,一是設定它的Text屬性,二是往它的InlineCollection裡新增內容。
可以發現我們能同時設定Text屬性,並添加InlineCollection資訊,但最後顯示的會是InlineCollection裡的資訊,並且不會對Text屬性的值產生影響。
那麼我們是否可以把文本值賦給Text屬性,然後再擷取相關值並在InlineCollection裡進行豎直設定呢。
那麼我們需要擷取TextBlock的TextChanged事件,可惜這個事件並不存在。
public class VerticalTextBlockBehavior : Behavior<TextBlock>
{
protected override void OnAttached()
{
base.OnAttached();
BindingOperations.SetBinding(this, VerticalTextBlockBehavior.InternalTextProperty, new Binding("Text") { Source = this.AssociatedObject });
this.VerticalText();
}
protected override void OnDetaching()
{
base.OnDetaching();
this.ClearValue(VerticalTextBlockBehavior.InternalTextProperty);
}
private void VerticalText()
{
var text = this.AssociatedObject.Text;
this.AssociatedObject.Inlines.Clear();
if (!string.IsNullOrEmpty(text))
{
foreach (var word in text)
{
this.AssociatedObject.Inlines.Add(new Run { Text = word.ToString() });
this.AssociatedObject.Inlines.Add(new LineBreak());
}
this.AssociatedObject.Inlines.RemoveAt(text.Length * 2 - 1);
}
}
private string InternalText
{
get { return (string)GetValue(InternalTextProperty); }
set { SetValue(InternalTextProperty, value); }
}
// Using a DependencyProperty as the backing store for InternalText. This enables animation, styling, binding, etc...
private static readonly DependencyProperty InternalTextProperty =
DependencyProperty.Register("InternalText", typeof(string), typeof(VerticalTextBlockBehavior),
new PropertyMetadata(OnInternalTextChanged));
private static void OnInternalTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source = d as VerticalTextBlockBehavior;
source.VerticalText();
}
}
我們在行為內部添加一個動態屬性,因為這個屬性並不需要對外公開,所以都設成Private就行了。然後在OnAttached方法裡把這個屬性綁定到TextBlock的Txet屬性,這樣當TextBlock的Text屬性發生變化時,我們這個內部屬性也會跟著變化,並最終回調到行為內部的方法VerticalText。
VerticalText裡的處理很簡單,擷取Text內容,然後每隔一個字元都插入一個斷行,這樣就會產生豎直排列文本的效果了。
PS:很多童鞋都知道控制項後台代碼綁定是通過FrameworkElement.SetBinding(DependencyProperty dp, Binding binding)方法來實現的,而對於不是繼承自FrameworkElement的類卻不知道如何處理了,其實就是BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding),而FrameworkElement.SetBinding裡的實現也是調用這個靜態方法實現的。