TextBlock内联上的WPF触发器

时间:2009-08-18 16:58:17

标签: c# wpf

我有一个TextBlock,我想显示一个用户名,并像这样发送电子邮件:

Firstname Lastname (Email)

但是,如果用户没有存档电子邮件,我不想放入(电子邮件)部分。我还想把电子邮件用斜体。通常情况下,我会使用TextBlock并为文本的各个部分添加运行,但我找不到从XAML动态更改TextBlock内联的方法。

我试过这个:

<TextBlock.Triggers>
<DataTrigger Binding="{Binding Path=HasEmail}" Value="True">

  <Setter Property="Inlines" TargetName="contactTagNameEmailTextBlock">
    <Setter.Value>
     <Run Text="{Binding Path=Firstname}" />
     <Run Text="{Binding Path=Lastname}" />
     <Run Text="(" />
     <Run Text="{Binding Path=Email}" />
     <Run Text=")" />
  </Setter.Value>

</Setter>
</DataTrigger>
</TextBlock.Triggers>

但VS抱怨该值设置不止一次(由于多次运行)。我怎么能绕过这个?或者,如果我可以在整个FrameworkElement上设置绑定,那将非常方便。例如,如果我可以在我的网格中放置一个占位符,我想放置一个自定义控件,我在这个绑定对象后面的代码中构造,那将是最好的。

感谢。

3 个答案:

答案 0 :(得分:5)

这样的事情应该有效:

<Window.Resources>
    <BooleanToVisibility x:Key="visibilityConverter"/>
</Window.Resources>

...

<TextBlock>
    <Run Text="{Binding Path=Firstname}" />
    <Run Text="{Binding Path=Lastname}" />
    <TextBlock Visibility="{Binding HasEmail, Converter={StaticResource visibilityConverter}}">
        <Run Text="(" />
        <Run Text="{Binding Path=Email}" />
        <Run Text=")" />
    </TextBlock>
</TextBlock>

答案 1 :(得分:2)

查看Multibinding和StringFormat

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat="{}{0}, {1}">
      <Binding Path="LastName" />
      <Binding Path="FirstName" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

如果没有电子邮件,您应该可以隐藏()。

答案 2 :(得分:0)

这里说的嵌套TextBlock元素的答案将导致布局问题。例如,外部TextBlock将不再适当地遵守TextTrimming设置。

这是一种更好的方法,通过触发器*为您提供运行设置的灵活性,这仍然允许正确的布局。

  

注意:我添加了格式化属性(Foreground,Bold)以显示您在此处使用Runs而不是简单的多重绑定的原因。使用运行(或任何内联)允许您格式化TextBlock的文本,但仍然让它尊重布局(即TextTrimming按预期工作等)。

<ContentControl x:Name="TextBlockPresenter">
    <TextBlock TextTrimming="CharacterEllipsis" IsHitTestVisible="False">
        <Run Text="{Binding Path=Firstname}" />
        <Run Text="{Binding Path=Lastname}" FontWeight="Bold" />
        <Run Text="(" Foreground="Gray" />
        <Run Text="{Binding Path=Email}" Foreground="Gray" />
        <Run Text=")" Foreground="Gray" />
    </TextBlock>
</ContentControl>

[SomeTriggerArea]

    <DataTrigger Binding="{Binding Path=HasEmail}" Value="False">
        <Setter TargetName="TextBlockPresenter" Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <TextBlock TextTrimming="CharacterEllipsis" IsHitTestVisible="False">
                        <Run Text="{Binding Path=Firstname}" />
                        <Run Text="{Binding Path=Lastname}" FontWeight="Bold" />
                    </TextBlock>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </DataTrigger>

[/SomeTriggerArea]

*从技术上讲,您不是通过触发器设置运行。您正在设置一个全新的模板,该模板具有定义了正确运行的TextBox。

  

如果你在控件中使用这样的运行来设置IsHitTestVisible为False也是一个好主意,你可能想要响应鼠标命中,然后走可视树(即你在哪里听一只右鼠标的TreeView) -down,遍历树以找到TreeViewItem并将IsSelected设置为true。)这是因为运行将响应鼠标,但它们不是FrameworkElement,因此当您使用e.OriginalSource调用VisualTreeHelper.GetParent时,您将得到一个例外。简单地禁止TextBlock参与鼠标事件可以避免这种情况。

相关问题