2014-02-19 202 views
3

我的问题与此类似:WPF Generate TextBlock Inlines但我没有足够的评论声望。这里是附加属性类:将文本绑定到附加属性

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

我使用这个附加属性类,并试图把它从一个字符串在我的视图模型应用到文本块,使文本识别如粗体直列值,下划线等类。我在我的文本块中有以下XAML:

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

但是,当我启动程序时,我在文本块中什么也没有。我也想将文本绑定到我的视图模型上的一个属性,但最终想获得一些东西...

对不起,这可能是一个新手问题,但我不明白为什么它不工作。它不会给我任何错误,只是不显示。如果我尝试绑定,它给我的错误:

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

+0

在StackOverflow上,你*应该*提问的问题,并*不*的意见和它的好,你提供了一个链接到的其他问题。但是,您需要提供* [重现问题所需的所有相关代码](http://stackoverflow.com/help/mcve)*,因为这是社区可能决定删除您的问题的原因之一。 – Sheridan

+0

好的不好意思,谢谢指点。我更新了包含我正在尝试使用的类的源代码,以及我想要使用它的更多细节... – sfaust

回答

4

首先,属性的类型必须是一个类的名称,而不是类型TextBlock

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

二,处理不调用,它必须在这里注册:

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

第三,一个例子来工作,你需要指定输入的字符串是这样的:

<Bold>My little text</Bold> 

工作例子如下:

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

最初是纯文本,点击Button将被分配到内联文本之后。

Example for MVVM version

要使用MVVM风格这个例子中,你需要在Model/ViewModel创建相应的属性,并将其与所连接的依赖属性像这样的关联:

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

属性,Model/ViewModel必须支持方法NotifyPropertyChanged

下面是一个完整的示例:

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 .

+0

我很抱歉,我没有忽略你,只是被拉开放出了火,现在又回到了这一点。谢谢你对理解正在发生的事情非常有帮助。但是,这需要您按下按钮才能将文本设置为新值。我真正需要的是将值绑定到我的视图模型上的属性,这可能会在界面打开时更改。我不明白我能做到这一点......有可能吗?此外,我正在upvoting一个非常有用的答案,但没有标记为答案,因为我正在寻找绑定件... – sfaust

+0

@sfaust:请参阅我的编辑。 –

+0

太棒了,标记为答案!我下载了你的例子,唯一的奇怪之处在于它一直给我两个自定义命名空间的'未定义的CLR命名空间'错误。我检查了他们,他们似乎是正确的,所以我不知道为什么。它建立和功能很好,但不知道为什么设计师显示这些错误... – sfaust