将文本绑定到附加属性 [英] Binding text to attached property

查看:60
本文介绍了将文本绑定到附加属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此类似:WPF Generate TextBlock Inlines 但我没有足够的声誉来评论.这是附加的属性类:

公共类附加{public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached("格式化文本",类型(字符串),类型(文本块),新 FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure));public static void SetFormattedText(DependencyObject textBlock,字符串值){textBlock.SetValue(FormattedTextProperty, value);}公共静态字符串 GetFormattedText(DependencyObject textBlock){返回(字符串)textBlock.GetValue(FormattedTextProperty);}私有静态无效FormattedTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){var textBlock = d as TextBlock;如果(文本块 == 空){返回;}var formattedText = (string)e.NewValue ??字符串.空;formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", 格式化文本);textBlock.Inlines.Clear();使用 (var xmlReader = XmlReader.Create(new StringReader(formattedText))){var 结果 = (Span)XamlReader.Load(xmlReader);textBlock.Inlines.Add(result);}}}

我正在使用这个附加的属性类并尝试将它应用到文本块,以使文本识别来自我的视图模型类中字符串的内联值,例如粗体、下划线等.我的文本块中有以下 XAML:

但是,当我启动程序时,文本块中什么也没有.我还想最终将文本绑定到我的视图模型上的一个属性,但想要先显示一些内容...

抱歉,这可能是一个新手问题,但我不知道为什么它不起作用.它在这里没有给我任何错误,只是没有出现.如果我尝试绑定,它会给我错误:

<块引用>

{无法在TextBlock"类型的SetFormattedText"属性上设置绑定".只能在 DependencyObject 的 DependencyProperty 上设置绑定"."}

解决方案

首先,属性的类型需要是类名,而不是类型TextBlock:

public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached("格式化文本",类型(字符串),typeof(TextBlock), <----- 这里

其次,handler没有被调用,必须在这里注册:

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

第三,一个工作示例,您需要像这样指定输入字符串:

我的小文字

工作示例如下:

XAML

<网格><TextBlock Name="TestText"this:AttachedPropertyTest.FormattedText="TestString"宽度=200"高度=100"TextWrapping="Wrap"/><按钮名称="测试按钮"宽度=100"高度=30"垂直对齐=顶部"内容=测试点击"Click="Button_Click"/></网格></窗口>

代码隐藏

公共部分类 MainWindow : Window{公共主窗口(){初始化组件();}私有无效Button_Click(对象发送者,RoutedEventArgs e){string inlineExpression = "<Bold>一旦我看到一只小鸟,就跳,跳,跳.</Bold>";AttachedPropertyTest.SetFormattedText(TestText, inlineExpression);}}公共类 AttachedPropertyTest{public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached("格式化文本",类型(字符串),typeof(AttachedPropertyTest),新 FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));public static void SetFormattedText(DependencyObject textBlock,字符串值){textBlock.SetValue(FormattedTextProperty, value);}公共静态字符串 GetFormattedText(DependencyObject textBlock){返回(字符串)textBlock.GetValue(FormattedTextProperty);}私有静态无效FormattedTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){var textBlock = d as TextBlock;如果(文本块 == 空){返回;}var formattedText = (string)e.NewValue ??字符串.空;formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", 格式化文本);textBlock.Inlines.Clear();使用 (var xmlReader = XmlReader.Create(new StringReader(formattedText))){var 结果 = (Span)XamlReader.Load(xmlReader);textBlock.Inlines.Add(result);}}}

初始为纯文本,点击Button后会被赋值为内嵌文本.

MVVM 版本示例

要在 MVVM 样式中使用此示例,您需要在 Model/ViewModel 中创建适当的属性并将其与附加的依赖属性相关联,如下所示:

Model/ViewModel 中的属性必须支持方法 NotifyPropertyChanged.

这是一个完整的示例:

AttachedProperty

公共类 TextBlockExt{public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached("格式化文本",类型(字符串),类型(TextBlockExt),新 FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));public static void SetFormattedText(DependencyObject textBlock,字符串值){textBlock.SetValue(FormattedTextProperty, value);}公共静态字符串 GetFormattedText(DependencyObject textBlock){返回(字符串)textBlock.GetValue(FormattedTextProperty);}私有静态无效FormattedTextPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){var textBlock = d as TextBlock;如果(文本块 == 空){返回;}var formattedText = (string)e.NewValue ??字符串.空;formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", 格式化文本);textBlock.Inlines.Clear();使用 (var xmlReader = XmlReader.Create(new StringReader(formattedText))){var 结果 = (Span)XamlReader.Load(xmlReader);textBlock.Inlines.Add(result);}}}

MainViewModel

公共类 MainViewModel : NotificationObject{私人字符串 _inlineText = "";公共字符串 InlineText{得到{返回_inlineText;}放{_inlineText = 值;NotifyPropertyChanged("InlineText");}}}

MainWindow.xaml

<Window.DataContext><ViewModels:MainViewModel/></Window.DataContext><网格><TextBlock Name="TestText"PropertiesExtension:TextBlockExt.FormattedText="{Binding Path=InlineText,模式=双向,UpdateSourceTrigger=PropertyChanged}"宽度=200"高度=100"TextWrapping="Wrap"/></网格></窗口>

代码隐藏(仅用于测试)

公共部分类 MainWindow : Window{公共主窗口(){初始化组件();}私有无效Window_ContentRendered(对象发送者,EventArgs e){MainViewModel mainViewModel = this.DataContext as MainViewModel;mainViewModel.InlineText = "<Bold>我看到一只小鸟,跳,跳,跳.</Bold>";}}

<块引用>

此示例可在此 link.

My question is similar to this: WPF Generate TextBlock Inlines but I don't have enough reputation to comment. Here is the attached property class:

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

    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);
        }
    }
}

I'm using this attached property class and trying to apply it to a textblock to make the text recognize inline values like bold, underline, etc from a string in my view model class. I have the following XAML in my textblock:

<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="Wrap" my:Attached.FormattedText="test" />

However I get nothing at all in the textblock when I start the program. I also would like to bind the text to a property on my view model eventually but wanted to get something to show up first...

Sorry this is probably a newbie question but I can't figure out why it's not working. It doesn't give me any error here, just doesn't show up. If I try to bind, it gives me the error:

{"A 'Binding' cannot be set on the 'SetFormattedText' property of type 'TextBlock'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."}

解决方案

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.

这篇关于将文本绑定到附加属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆