我正在尝试生成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不起作用。
•转换器甚至没有被调用(我在它上面放了一个断点)所以看起来绑定/ datatrigger就是没有触发。
之前有人做过这样的事吗?如果是这样,你有没有设法让它工作?在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();
}
};
答案 0 :(得分: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”没有绿色背景的问题。
现在,您的转换器示例还有一些其他问题:
ContainsTextConverter
,但您引用了{StaticResource ContainsBoolConverter}
。Value="False"
。null
。它会被调用每个BindableRun
,但如果在设置DataContext之前加载XAML,则可以使用null
调用它。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
都正常工作。
答案 1 :(得分:0)
要获得一个单词的检查,您需要编写一个这样的触发器:
<Trigger Property="BindableText" Value="text">
<Setter Property="Background" Value="GreenYellow" />
</Trigger>
现在,如果字符串是text
,则触发我们的触发器。
关于Converter
,我尝试了不同的选项,但传递给Converter
的值始终为Null
。然后我决定走另一条路。之后,您为属性BindableText
创建了一个类,因此我决定再添加两个类:
一个用于验证传递给转换器的字符串的属性(StackOverflow
字符串)。
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