Binding text to attached property

风格不统一 提交于 2019-12-05 23:57:41

First, the type of property needs to be a class name, not the type TextBlock:

public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
    "FormattedText",
    typeof(string),
    typeof(TextBlock), <----- Here

Second, the handler is not called, it must be registered here:

new FrameworkPropertyMetadata(string.Empty, 
                              FrameworkPropertyMetadataOptions.AffectsMeasure,
                              YOUR_PropertyChanged_HANDLER)

Thirdly, an example to work, you need to specify the input string like this:

<Bold>My little text</Bold>

Working example is below:

XAML

<Window x:Class="InlineTextBlockHelp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:InlineTextBlockHelp"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <TextBlock Name="TestText"
                   this:AttachedPropertyTest.FormattedText="TestString"
                   Width="200"
                   Height="100" 
                   TextWrapping="Wrap" />

        <Button Name="TestButton"
                Width="100"
                Height="30"
                VerticalAlignment="Top"
                Content="TestClick" 
                Click="Button_Click" />
    </Grid>
</Window>

Code-behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string inlineExpression = "<Bold>Once I saw a little bird, go hop, hop, hop.</Bold>";
        AttachedPropertyTest.SetFormattedText(TestText, inlineExpression);
    }
}

public class AttachedPropertyTest
{
    public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
        "FormattedText",
        typeof(string),
        typeof(AttachedPropertyTest),
        new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));

    public static void SetFormattedText(DependencyObject textBlock, string value)
    {
        textBlock.SetValue(FormattedTextProperty, value);
    }

    public static string GetFormattedText(DependencyObject textBlock)
    {
        return (string)textBlock.GetValue(FormattedTextProperty);
    }

    private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBlock = d as TextBlock;

        if (textBlock == null)
        {
            return;
        }

        var formattedText = (string)e.NewValue ?? string.Empty;
        formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);

        textBlock.Inlines.Clear();
        using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
        {
            var result = (Span)XamlReader.Load(xmlReader);
            textBlock.Inlines.Add(result);
        }
    }
}

Initially be plain text, after clicking on the Button will be assigned to inline text.

Example for MVVM version

To use this example in MVVM style, you need to create the appropriate property in the Model/ViewModel and associate it with the attached dependency property like this:

<TextBlock Name="TestText"
           PropertiesExtension:TextBlockExt.FormattedText="{Binding Path=InlineText, 
                                                                    Mode=TwoWay,
                                                                    UpdateSourceTrigger=PropertyChanged}"
           Width="200"
           Height="100" 
           TextWrapping="Wrap" />

Property in Model/ViewModel must support method NotifyPropertyChanged.

Here is a full sample:

AttachedProperty

public class TextBlockExt
{
    public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
        "FormattedText",
        typeof(string),
        typeof(TextBlockExt),
        new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));

    public static void SetFormattedText(DependencyObject textBlock, string value)
    {
        textBlock.SetValue(FormattedTextProperty, value);
    }

    public static string GetFormattedText(DependencyObject textBlock)
    {
        return (string)textBlock.GetValue(FormattedTextProperty);
    }

    private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBlock = d as TextBlock;

        if (textBlock == null)
        {
            return;
        }

        var formattedText = (string)e.NewValue ?? string.Empty;
        formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);

        textBlock.Inlines.Clear();
        using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
        {
            var result = (Span)XamlReader.Load(xmlReader);
            textBlock.Inlines.Add(result);
        }
    }
}

MainViewModel

public class MainViewModel : NotificationObject
{
    private string _inlineText = "";

    public string InlineText
    {
        get
        {
            return _inlineText;
        }

        set
        {
            _inlineText = value;
            NotifyPropertyChanged("InlineText");
        }
    }
}

MainWindow.xaml

<Window x:Class="InlineTextBlockHelp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ViewModels="clr-namespace:InlineTextBlockHelp.ViewModels"
        xmlns:PropertiesExtension="clr-namespace:InlineTextBlockHelp.PropertiesExtension"
        Title="MainWindow" Height="350" Width="525"
        ContentRendered="Window_ContentRendered">

    <Window.DataContext>
        <ViewModels:MainViewModel />
    </Window.DataContext>

    <Grid>
        <TextBlock Name="TestText"
                   PropertiesExtension:TextBlockExt.FormattedText="{Binding Path=InlineText, 
                                                                            Mode=TwoWay,
                                                                            UpdateSourceTrigger=PropertyChanged}"
                   Width="200"
                   Height="100" 
                   TextWrapping="Wrap" />
    </Grid>
</Window>

Code-behind (just for test)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_ContentRendered(object sender, EventArgs e)
    {
        MainViewModel mainViewModel = this.DataContext as MainViewModel;

        mainViewModel.InlineText = "<Bold>Once I saw a little bird, go hop, hop, hop.</Bold>";
    }
}

This example is available at this link.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!