0

我正在尝试生成一个 FlowDocument,并希望在某些文本运行包含特定字符串时突出显示它们。我正在使用BindableRun类来确保我可以更新 Run 文本值(尽管我只在构造时设置它们,所以 Run 的 vanilla 实例应该没问题)。

本质上,我想这样做:

 <FlowDocument Name="FlowDoc" FontFamily="{x:Static SystemFonts.CaptionFontFamily}" 
                  Background="{x:Static SystemColors.ControlBrush}" 
                  FontSize="{x:Static SystemFonts.SmallCaptionFontSize}"
                  TextAlignment="Left">
      <FlowDocument.Resources>
        <Style TargetType="{x:Type local:BindableRun}">
          <!-- 1. Style all BindableRuns with a pink background by default -->
          <Setter Property="Background" Value="HotPink"/>

          <Style.Triggers>

            <!-- 2. Style BindableRuns where Text=Hello to have a green background-->
            <DataTrigger Binding="{Binding BoundText}" Value="Hello">
              <Setter Property="Background" Value="GreenYellow"/>
            </DataTrigger>
            <!-- 3. Fire a Datatrigger with parameterised converter to change 
                  text to Orange if the text contains 'StackOverflow'-->
            <DataTrigger Binding="{Binding BoundText, 
                           Converter={StaticResource ContainsBoolConverter},
                           ConverterParameter=StackOverflow}" Value="False">
              <Setter Property="Foreground" Value="Orange"/>
            </DataTrigger>
          </Style.Triggers>
        </Style>
      </FlowDocument.Resources>
    </FlowDocument>

现在,当我尝试使用上面的 Xaml 时:

• 更改BindableRun 对象(即#1)背景的样式效果很好——因此FlowDocument 的内容是我所期望的

• 针对 BindableRun 对象的 BountText 属性的 DataTriggers 不起作用。

• 转换器甚至没有被调用(我已经在它上面设置了一个断点),所以看起来绑定/数据触发器只是没有触发。

以前有人做过这样的事情吗?如果是这样,你有没有设法让它工作?关于 SO 等的 FlowDocument 示例并不多,因此我没有设法追踪任何其他尝试(无论成功与否)在 Run 的 Text 属性上使用 DataTriggers 的人。

作为参考,这是我正在使用的 Contains 转换器(尽管它根本不会触发,所以它是否正确并不重要;))。

public class ContainsTextConverter : IValueConverter
{
    public object Convert( object value, Type t, object parameter, CultureInfo culture )
    {
        String input = value.ToString();
        string param = parameter.ToString();

        return input.IndexOf( param, StringComparison.OrdinalIgnoreCase ) != -1;
    }

    public object ConvertBack( object value, Type t, object parameter, CultureInfo culture )
    {
        // Don't care about this
        throw new NotSupportedException();
    }
};
4

2 回答 2

1

添加RelativeSource={RelativeSource Self}到您的两个DataTrigger绑定中。默认情况下,绑定会查找控件的DataContext. 要使其查找控件的属性,您需要该RelativeSource参数。

    <!-- 2. Style BindableRuns where Text=Hello to have a green background-->
    <DataTrigger Binding="{Binding BoundText, RelativeSource={RelativeSource Self}}" Value="Hello">
        <Setter Property="Background" Value="GreenYellow"/>
    </DataTrigger>

    <!-- 3. Fire a Datatrigger with parameterised converter to change text to Orange if the text contains 'StackOverflow'-->
    <DataTrigger Binding="{Binding BoundText, RelativeSource={RelativeSource Self},
            Converter={StaticResource ContainsTextConverter},
            ConverterParameter=StackOverflow}" Value="True">
        <Setter Property="Foreground" Value="Orange"/>
    </DataTrigger>

这将解决“Hello”没有绿色背景的问题。

现在,您的转换器示例还有几个额外的问题:

  1. 转换器已命名ContainsTextConverter,但您引用{StaticResource ContainsBoolConverter}.
  2. 当您说您确实希望文本包含参数时,您指定Value="False"了条件。
  3. 您需要确保值不在null转换器中。它会为您的每个BindableRuns 调用,但null如果在设置 DataContext 之前加载 XAML,则可能会调用它。
public object Convert( object value, Type t, object parameter, CultureInfo culture )
{
    if( value != null )
    {
        return (value as String).IndexOf( parameter as String, StringComparison.OrdinalIgnoreCase ) != -1;
    }
    else return false;
}

进行这些更改,您会发现两者都DataTrigger有效。

于 2013-08-23T20:15:23.677 回答
0

要获得一个单词的检查,您需要编写如下触发器:

<Trigger Property="BindableText" Value="text">
    <Setter Property="Background" Value="GreenYellow" />
</Trigger>   

现在,如果字符串是text,则触发我们的触发器。

关于Converter,我尝试了不同的选项,但传递给 的值Converter总是Null。然后我决定走另一条路。之后,您为 property 创建了一个类BindableText,所以我决定再添加两个:

  1. 一个属性来验证您传递给转换器的字符串(StackOverflow字符串)。

  2. type 的一个属性Brush,用于设置颜色。

所以,我的完整例子:

XAML

<Grid>
    <FlowDocumentScrollViewer>
        <FlowDocument>
            <FlowDocument.Resources>
                <Style TargetType="{x:Type local:BindableExtender}">
                    <Style.Triggers>
                        <Trigger Property="BindableText" Value="text">
                            <Setter Property="Background" Value="GreenYellow"/>
                        </Trigger>                                                        
                    </Style.Triggers>
                </Style>
            </FlowDocument.Resources>

            <Paragraph>
                Binding string:

                <local:BindableExtender BindableText="{Binding ElementName=MyTextBox, Path=Text}"
                                        CompareText="StackOverflow"
                                        ForegroundBrush="OrangeRed" />
            </Paragraph>

            <BlockUIContainer>
                <TextBox Name="MyTextBox" Text="text"/>
            </BlockUIContainer>
        </FlowDocument>
    </FlowDocumentScrollViewer>
</Grid>

Code behind

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

public class BindableExtender : Run
{
    #region BindableText declaration

    public String BindableText
    {
        get 
        { 
            return (string)GetValue(BindableTextProperty); 
        }

        set 
        { 
            SetValue(BindableTextProperty, value); 
        }
    }

    public static readonly DependencyProperty BindableTextProperty =
        DependencyProperty.Register("BindableText",
            typeof(string),
            typeof(BindableExtender),
            new UIPropertyMetadata(null, BindableTextProperty_PropertyChanged));

    private static void BindableTextProperty_PropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        BindableExtender MyRun = dependencyObject as BindableExtender;

        if (dependencyObject is BindableExtender)
        {
            MyRun.Text = (string)e.NewValue;
            string bind = (string)e.NewValue;

            // Check the two strings
            if (bind.IndexOf(MyRun.CompareText, StringComparison.OrdinalIgnoreCase) != -1)
            {
                MyRun.Foreground = MyRun.ForegroundBrush;
            }
            else
            {
                MyRun.Foreground = Brushes.Black;
            }
        }
    }

    #endregion BindableText declaration

    #region CompareText declaration

    public String CompareText
    {
        get 
        { 
            return (string)GetValue(CompareProperty); 
        }

        set 
        {
            SetValue(CompareProperty, value); 
        }
    }

    public static readonly DependencyProperty CompareProperty =
        DependencyProperty.Register("CompareText",
            typeof(string),
            typeof(BindableExtender),
            new UIPropertyMetadata(null, CompareProperty_PropertyChanged));

    private static void CompareProperty_PropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        BindableExtender MyRun = dependencyObject as BindableExtender;
        string CompareString = e.NewValue as string;

        // Save the value in CompareText property
        MyRun.CompareText = CompareString;
    }

    #endregion

    #region ForegroundBrush declaration

    public Brush ForegroundBrush
    {
        get
        {
            return (Brush)GetValue(ForegroundBrushProperty);
        }

        set
        {
            SetValue(ForegroundBrushProperty, value);
        }
    }

    public static readonly DependencyProperty ForegroundBrushProperty =
        DependencyProperty.Register("ForegroundBrush",
            typeof(Brush),
            typeof(BindableExtender),
            new UIPropertyMetadata(null, ForegroundBrushProperty_PropertyChanged));

    private static void ForegroundBrushProperty_PropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        BindableExtender MyRun = dependencyObject as BindableExtender;
        Brush NewForegroundBrush = e.NewValue as Brush;

        // Save the value in ForegroundBrush property
        MyRun.ForegroundBrush = NewForegroundBrush;
    }

    #endregion
}

Output #1

在此处输入图像描述

Output #2

在此处输入图像描述

于 2013-08-24T10:05:25.837 回答