【问题标题】:How to set the tooltip of a contentpresenter to the value it is showing?如何将 contentpresenter 的工具提示设置为其显示的值?
【发布时间】:2017-05-18 17:00:20
【问题描述】:

我们有一个带有自定义ListBoxItemTemplateListBox,它使用ListBoxDisplayMemberPath 属性显示一些信息。

ListBoxItemTemplate 内部有一个ContentPresenter

我们需要做的就是设置ContentPresenter 的Tooltip 属性以显示与ContentPresenter 相同的内容。

我试过这样做:

<ContenPresenter Tooltip={Path Content, RelativeSource={RelativeSource Self}}/>

但我得到的上下文没有 DisplayMemberPath 逻辑(整个 datacontext 对象)。

如何获取应用了“DisplayMemberPath”的 ContentPresenter 显示的值?

编辑

这里没有Tooltip的样式(控件设置了这个样式和DisplayMemberPath属性绑定):

<Style x:Key="CheckListBoxStyle" TargetType="{x:Type ListBox}" >
    <Setter Property="SelectionMode" Value="Multiple" />
    <Setter Property="ItemContainerStyle" Value="{StaticResource CheckListBoxItemStyle}"/>
    <Setter Property="Width" Value="177"/>
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="Height" Value="70"/>
</Style>

<Style x:Key="CheckListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
    <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
    <Setter Property="Padding" Value="2,0,0,0" />
    <Setter Property="Template">

        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border x:Name="Bd"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            SnapsToDevicePixels="true">
                    <CheckBox HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Tag="CheckBox1">
                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </CheckBox>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

  • 我认为不可能同时为列表框同时使用 DisplayMemberPath 属性和 ItemTemplate。能否请您出示您的代码?

标签: c# wpf data-binding binding


【解决方案1】:

如何获取应用了“DisplayMemberPath”的 ContentPresenter 显示的值?

您不能在纯 XAML 中动态地执行此操作。如果您知道 DisplayMemberPath 属性的值,您可以直接绑定到该属性:

<CheckBox HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                          IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Tag="CheckBox1"
                                                          ToolTip="{Binding Path=Content.Name, ElementName=cp}">
    <ContentPresenter x:Name="cp" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</CheckBox>

但你不能做类似ToolTip="{Binding Path=Content.[DisplayMemberPath], ElementName=cp}"的事情。

您将不得不编写一些代码来实现这一点。例如,您可以使用转换器:

public class ContentConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string path = values[0] as string;
        object dataObject = values[1];

        if(!string.IsNullOrEmpty(path) && dataObject != null)
            return dataObject.GetType().GetProperty(path).GetValue(dataObject).ToString();

        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

<ListBox x:Name="lb11" DisplayMemberPath="Name">
    <ListBox.Resources>
        <local:ContentConverter x:Key="conv" />
    </ListBox.Resources>
    <ListBox.Style>
        <Style TargetType="{x:Type ListBox}" >
            <Setter Property="SelectionMode" Value="Multiple" />
            <Setter Property="ItemContainerStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type ListBoxItem}">
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
                        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
                        <Setter Property="Padding" Value="2,0,0,0" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                    <Border x:Name="Bd" Background="{TemplateBinding Background}"
                                                    BorderBrush="{TemplateBinding BorderBrush}"
                                                    BorderThickness="{TemplateBinding BorderThickness}"
                                                    Padding="{TemplateBinding Padding}"
                                                    SnapsToDevicePixels="true">
                                        <CheckBox HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                          IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Tag="CheckBox1">
                                            <CheckBox.ToolTip>
                                                <MultiBinding Converter="{StaticResource conv}">
                                                    <Binding Path="DisplayMemberPath" RelativeSource="{RelativeSource AncestorType=ListBox}"/>
                                                    <Binding Path="Content" ElementName="cp"/>
                                                </MultiBinding>
                                            </CheckBox.ToolTip>
                                            <ContentPresenter x:Name="cp" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                        </CheckBox>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Setter.Value>
            </Setter>
            <Setter Property="Width" Value="177"/>
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="Height" Value="70"/>
        </Style>
    </ListBox.Style>
</ListBox>

【讨论】:

  • 好的,谢谢。我明白你的意思。我将尝试创建一个附加属性,因为我不喜欢将转换器与数据上下文对象(内容)一起使用,因为看起来你正在做更多的视觉转换。还是谢谢!
  • 我正在使用反射从数据对象中获取具有动态名称的属性的值。如果您想使用 DisplayMemberPath 的 string 值来获取实际值,您将无法避免这种情况。
  • 不,没关系。它更多的是关注点分离问题。我的观点是 Converter 应该只有可视化逻辑并将 Datacontext 对象传递给 Converter 然后它正在执行 VM 逻辑。
  • 这很公平,但我的主要观点是,您不能在模板本身的 XAML 标记中执行此操作。您是使用转换器还是附加属性来获取工具提示的内容完全取决于您:)
【解决方案2】:

由于您在 Template 中定义了ContentPresenter,因此您无法访问 Binding 中的内容。根据DataContext 分布,您已经处于内容级别。所以它没有用,我想将ContentPresenter 更改为ContentControlToolTip 如下所示会起作用

<ContentControl Tooltip={Binding}/>

如果我错了,请纠正我。

【讨论】:

  • 在 ControlTemplate 中添加 ContentControl 不起作用。显示文本和工具栏:\
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
相关资源
最近更新 更多