tooltip 相关问题

工具提示是GUI(图形用户界面)元素,当鼠标指针悬停在GUI中的项目上并提供一些上下文信息或说明时,它通常会弹出。

ExtJS - 网格单元工具提示

我正在尝试为单元格创建一个工具提示。下面的代码做到了这一点,但工具提示仅出现在 Click(在 mozilla 中)上,而在 IE 中,工具提示出现在 mouseOver 上,但显示最后单击的单元格的值。 我想要...

回答 1 投票 0

所有时期的折线图工具提示

我希望有人能进一步帮助我, 我在 Power BI 中有一个“成本”选项卡,其中包含一个矩阵,行中包含“帐户”,值包含“金额”。这些值由同一台上的周期切片器控制...

回答 1 投票 0

当视觉样式打开时,为 Windows 本机气球工具提示设置颜色

我有一个遗留代码,用于创建 Windows 本机气球工具提示。在以前版本的 Windows 中,我可以使用 TTM_SETTIPBKCOLOR 和

回答 1 投票 0

React 仅针对有省略号的文本显示 Material-UI 工具提示

寻找一种方法,让material-ui的工具提示仅在文本被省略号截断(溢出)时才展开表格单元格中的文本。 目前在我的表格中有一个像这样的单元格: 寻找一种方法让material-ui的工具提示在表格单元格中展开文本仅如果文本被省略号截断(溢出)。 目前在我的表格中有一个像这样的单元格: <TableCell className={classes.descriptionCell}>{row.description}</TableCell> 我的descriptionCell样式是这样的: descriptionCell: { whiteSpace: 'nowrap', maxWidth: '200px', overflow: 'hidden', textOverflow: 'ellipsis' } 这使得文本在该表中的行为方式符合我希望的方式,但我希望能够悬停并在工具提示中查看其余部分,最好是 Material-UI 的内置工具提示组件。 我知道这里有一个包 https://www.npmjs.com/package/react-ellipsis-with-tooltip 应该可以做到这一点,但它使用引导工具提示,而不是材料 UI。 离开@benjamin.keen 的回答。这是一个独立的功能组件,它只是他的答案的扩展,使用钩子来执行比较功能。 import React, { useRef, useEffect, useState } from 'react'; import Tooltip from '@material-ui/core/Tooltip'; const OverflowTip = props => { // Create Ref const textElementRef = useRef(); const compareSize = () => { const compare = textElementRef.current.scrollWidth > textElementRef.current.clientWidth; console.log('compare: ', compare); setHover(compare); }; // compare once and add resize listener on "componentDidMount" useEffect(() => { compareSize(); window.addEventListener('resize', compareSize); }, []); // remove resize listener again on "componentWillUnmount" useEffect(() => () => { window.removeEventListener('resize', compareSize); }, []); // Define state and function to update the value const [hoverStatus, setHover] = useState(false); return ( <Tooltip title={props.value} interactive disableHoverListener={!hoverStatus} style={{fontSize: '2em'}} > <div ref={textElementRef} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }} > {props.someLongText} </div> </Tooltip> ); }; export default OverflowTip; 基于benjamin.keen的回答,这是他的代码的功能版本: import React, { useRef, useState, useEffect } from 'react'; import Tooltip from '@material-ui/core/Tooltip'; const OverflowTip = ({ children }) => { const [isOverflowed, setIsOverflow] = useState(false); const textElementRef = useRef(); useEffect(() => { setIsOverflow(textElementRef.current.scrollWidth > textElementRef.current.clientWidth); }, []); return ( <Tooltip title={children} disableHoverListener={!isOverflowed}> <div ref={textElementRef} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }} > {children} </div> </Tooltip> ); }; 我今天遇到了同样的问题,@vijay-menon 的回答非常有帮助。这是一个用于同一件事的简单独立组件: import React, { Component } from 'react'; import Tooltip from '@material-ui/core/Tooltip'; class OverflowTip extends Component { constructor(props) { super(props); this.state = { overflowed: false }; this.textElement = React.createRef(); } componentDidMount () { this.setState({ isOverflowed: this.textElement.current.scrollWidth > this.textElement.current.clientWidth }); } render () { const { isOverflowed } = this.state; return ( <Tooltip title={this.props.children} disableHoverListener={!isOverflowed}> <div ref={this.textElement} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}> {this.props.children} </div> </Tooltip> ); } } 使用示例: <OverflowTip> some long text here that may get truncated based on space </OverflowTip> 一个麻烦的是,如果页面中元素的空间动态变化(例如页面调整大小或动态 DOM 更改),它不会确认新空间并重新计算它是否溢出。 Tippy 等其他工具提示库有一个在“尝试”打开工具提示时触发的方法。这是进行溢出检查的完美位置,因为无论文本元素的 DOM 宽度是否发生变化,它都始终有效。不幸的是,使用 Material UI 提供的 API 来做到这一点比较麻烦。 请找到下面的codesandbox - https://codesandbox.io/s/material-demo-p2omr 我在这里使用ref来获取TableCell DOM节点,然后比较scrollWidth和clientWidth来确定是否必须显示Tooltip。(这是基于答案here) 我已将“rowref”(具有引用的属性)和“open”(禁用/启用工具提示)添加为行的新属性。我不知道您的数据来自哪里,但我假设您可以将这些属性添加到行中。 还有一点需要注意,我只是设置“disableHoverListener”属性来禁用 tooltip 。还有其他道具 - "disableFocusListener" 和 "disableTouchListener" ,如果你想使用它们。更多信息这里 希望这对您有用。如果您对代码有任何疑问,请告诉我。 基于@Dheeraj 答案 - 这是非常接近他的组件,但在类型脚本版本中,并且更有意义的道具名称: import React, { useRef, useEffect, useState } from 'react'; import Tooltip from '@material-ui/core/Tooltip'; interface Props { tooltip: string; text: string; } const OverflowTooltip = (props: Props) => { const textElementRef = useRef<HTMLInputElement | null>(null); const compareSize = () => { const compare = textElementRef.current.scrollWidth > textElementRef.current.clientWidth; setHover(compare); }; useEffect(() => { compareSize(); window.addEventListener('resize', compareSize); }, []); useEffect(() => () => { window.removeEventListener('resize', compareSize); }, []); const [hoverStatus, setHover] = useState(false); return ( <Tooltip title={props.tooltip} interactive disableHoverListener={!hoverStatus} > <div ref={textElementRef} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }} > {props.text} </div> </Tooltip> ); }; export default OverflowTooltip; 我们这样使用它: <OverflowTooltip tooltip={'tooltip message here'} text={'very long text here'} /> 如果有人需要 TypScript 版本: import { Tooltip, Typography, TypographyProps } from "@mui/material"; import { FC, ReactChild, useEffect, useRef, useState } from "react"; export interface OverflowTypograpyProps extends TypographyProps { children: ReactChild; } export const OverflowTypograpy: FC<OverflowTypograpyProps> = ({ children, ...props }) => { const ref = useRef<HTMLSpanElement>(null); const [tooltipEnabled, setTooltipEnabled] = useState(false); useEffect(() => { const compareSize = () => { if (ref.current) { const compare = ref.current.scrollWidth > ref.current.clientWidth; setTooltipEnabled(compare); } }; compareSize(); window.addEventListener("resize", compareSize); return () => window.removeEventListener("resize", compareSize); }, []); return ( <Tooltip title={children} disableHoverListener={!tooltipEnabled}> <Typography ref={ref} noWrap overflow="hidden" textOverflow="ellipsis" {...props} > {children} </Typography> </Tooltip> ); }; 我认为你不需要陷入任何副作用的陷阱。顶部的帖子建议在窗口上放置一个事件侦听器,该事件侦听器会在每次鼠标移动事件时触发。我们可以定义一些回调并将它们传递给 onMouseEnter 和 onMouseLeaveimport React, { useState, MouseEvent } from "react"; import Tooltip, { TooltipProps } from "@mui/material/Tooltip"; export const OverflowTooltip = ({ children, ...props }: TooltipProps) => { const [tooltipEnabled, setTooltipEnabled] = useState(false); const handleShouldShow = ({ currentTarget }: MouseEvent<Element>) => { if (currentTarget.scrollWidth > currentTarget.clientWidth) { setTooltipEnabled(true); } }; const hideTooltip = () => setTooltipEnabled(false); return ( <Tooltip onMouseEnter={handleShouldShow} onMouseLeave={hideTooltip} disableHoverListener={!tooltipEnabled} {...props} > <div style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }} > {children} </div> {children} </Tooltip> ); }; 定义文本是否溢出的方法在接受的答案中存在缺陷。由于 scrollWidth 和 clientWidth 返回四舍五入的整数值,当它们之间的差异很小时,我们将得到相等的值,并且工具提示将不起作用。问题是省略号也被算作 clientWidth,所以当我们只有一个或多个字符溢出时,我们会看到省略号,但 scrollWidth 和 clientWidth 是相等的。 以下是帮助我以分数精度确定 scrollWidth 和 clientWidth 并解决此问题的解决方案:import React, { useRef, useState, useEffect } from 'react'; import { Tooltip } from '@material-ui/core'; const OverflowTooltip = ({ children }) => { const textElementRef = useRef(); const checkOverflow = () => { // Using getBoundingClientRect, instead of scrollWidth and clientWidth, to get width with fractional accuracy const clientWidth = textElementRef.current.getBoundingClientRect().width textElementRef.current.style.overflow = 'visible'; const contentWidth = textElementRef.current.getBoundingClientRect().width textElementRef.current.style.overflow = 'hidden'; setIsOverflow(contentWidth > clientWidth); } useEffect(() => { checkOverflow(); window.addEventListener('resize', checkOverflow) return () => { window.removeEventListener('resize', checkOverflow) } }, []); const [isOverflowed, setIsOverflow] = useState(false); return ( <Tooltip title={children} disableHoverListener={!isOverflowed}> <span ref={textElementRef} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }} > {children} </span> </Tooltip> ); }; export default OverflowTooltip 从上述所有答案中汲取灵感,即使在调整大小时我也能正常工作。诀窍是让它成为一个受控的工具提示。 您也可以在此处检查实现https://codesandbox.io/s/control-tooltip-for-text-ellipsis-mkj1vp (请调整输出窗口大小以查看省略号效果) import { useState, MouseEvent } from "react"; import { Tooltip, Typography } from "@mui/material"; const LONGLABEL = "abcdefgh ijklmn opqrst uvwzyz"; export const OverflowTooltipExample = () => { const [tooltipEnabled, setTooltipEnabled] = useState(false); const handleShouldShow = ({ currentTarget }: MouseEvent<Element>) => { if (currentTarget.scrollWidth > currentTarget.clientWidth) { setTooltipEnabled(true); } }; return ( <Tooltip title={LONGLABEL} open={tooltipEnabled} onClose={() => setTooltipEnabled(false)} > <Typography onMouseEnter={handleShouldShow} noWrap> {LONGLABEL} </Typography> </Tooltip> ); }; 如果您只想在内容溢出时显示工具提示,则可以使用此方法。 需要 useEffect(),因为 ref.current 最初为 null,但是当组件安装时它会被设置,您可以基于它抓取 html 元素。interface MyInterface { content: Content; } export const MyComponent: React.FC<MyInterface> = ({ content }) => { const ref = useRef(null); const [showTooltip, setShowTooltip] = useState(false); useEffect(() => { if (!ref.current) return; const div = ref.current as HTMLDivElement; const isOverflow = div.offsetWidth < div.scrollWidth; setShowTooltip(isOverflow); }, []); const renderContent = () => ( <div ref={ref}> content </div> ); return ( <> {ref.current && showTooltip ? ( <Tooltip title={content.value}> {renderContent()} </Tooltip> ) : ( renderContent() )} </> ); }; 我的解决方案:注意==>对于span来说scrollWidth和clientWidth将为零,我们应该使用div import React, { useRef, useState, useEffect } from 'react' import { Tooltip, styled } from '@mui/material' const StyledDiv = styled('div')({ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', }) const OverflowTooltip = ({ children }) => { const textElementRef = useRef() const checkOverflow = () => { setIsOverflow(textElementRef.current.scrollWidth > textElementRef.current.clientWidth) } useEffect(() => { checkOverflow() window.addEventListener('resize', checkOverflow) return () => { window.removeEventListener('resize', checkOverflow) } }, []) const [isOverflowed, setIsOverflow] = useState(false) return ( <StyledDiv ref={textElementRef} > <Tooltip title={children} disableHoverListener={!isOverflowed}> {children} </Tooltip> </StyledDiv> ) } export default OverflowTooltip

回答 11 投票 0

Antd:如何将工具提示添加到表格的列标题

我想为表格的每个列标题添加自定义工具提示 我尝试使用标题工具提示,但这不会在整个单元格区域触发 { 标题: } 有没有简单的方法...

回答 1 投票 0

类型错误:无法设置未定义的属性(设置“钩子”)

TypeError:无法设置未定义的属性(设置“hook”) 我正在开发 Nextjs 应用程序,但使用 antd 库时出现此错误。我正在使用模态组件和工具提示组件

回答 3 投票 0

Mattooltip:如何使框适合文本?

我想将这段文本显示为工具提示。如果没有样式(只是将字体大小定义为 16px),它看起来像这样: 我真正想要的是让文本显示在一行中 - 所以我设置了

回答 1 投票 0

将 Syncfusion 工具提示格式与轴分开

我希望能够以不同于 y 轴的方式设置工具提示中的文本格式。 y 轴不显示分。我只想在工具提示上显示美分。格式化完成...

回答 1 投票 0

如何在工具提示数据中显示图像?

我找到了一个示例工具提示 html css,它正是我正在寻找的。但我不想显示文本,而是想显示图像。链接在这里。 代码笔链接 我们也可以在数据上显示图像吗...

回答 1 投票 0

为什么 Plotly.js 散点图中工具提示显示在错误的点上?

我在 Plotly 社区发布了这个问题:https://community.plotly.com/t/why-does-the-tooltip-show-on-the-wrong-point-in-scatter-plot/ 78835。我再次在这里发布以获得更多

回答 1 投票 0

如何使引导工具提示保持可见,直到单击链接

我有一个链接,当用户有一些新通知时,我将使用该链接作为通知,我将通过显示工具提示(twitter bootstrap 工具提示)来通知用户。我想要实现的是...

回答 3 投票 0

一键颤动工具提示

我想在单击时显示工具提示,而不是长按时显示。 谁能帮我这个? 工具提示( 消息:e.title, 孩子:卡( 语义容器:true, 孩子:填充( 填充:

回答 3 投票 0

在 VsCode 中禁用工具提示

我是个新人,但在此处搜索并尝试禁用 CodeLens 后并没有解决我的问题。 我从 VsCode 中的 python 数据科学开始,例如,如果我要创建一个 Numpy 数组,它会显示...

回答 1 投票 0

如何调整Material UI Tooltip字体大小?

我用 Material UI 实现了一个工具提示,但字体太小了。我无法用 .scss 更改它。 从“反应”导入反应; 导入“./InfoTooltip.scss”; 导入信息图标

回答 5 投票 0

当文本因溢出而被修剪时显示工具提示

我在文本顶部显示工具提示,让用户看到人员的全名,但无论文本是否溢出,它都会显示工具提示: 子项:工具提示( 消息:fullNameWit...

回答 1 投票 0

向 MatTooltip 添加箭头

我想在 Angular 16 上使用 MatTooltip 添加一个箭头。但是由于某种原因,使用箭头的伪元素覆盖材质并不像许多帖子中建议的那样工作。 这是我的同事...

回答 1 投票 0

如何在动态元素上绑定引导工具提示

使用Bootstrap工具提示时,我们需要编写这样的代码才能具有工具提示功能: $(".showtooltip").tooltip(); 但问题是,每次新的 c 时,我们都需要重新运行该代码...

回答 7 投票 0

在AG网格中,仅显示溢出单元格的文本的工具提示

我有一个有两列的农业网格表。对于第一列,我显示名称和区域。当用户将鼠标悬停在名称和区域上时,我希望名称显示在工具提示中。 ...

回答 1 投票 0

应用工具提示菜单选项后,显示在窗口中的不同位置,而不是材料 ui 中的按钮图标下方。同样的问题怎么解决

我正在尝试将工具提示应用于选项菜单图标,但它没有按我预期的方式工作。 我的代码是: 导出默认函数 FadeMenu() { const [anchorEl, setAnchorEl] = React.useState(null) ...

回答 1 投票 0

创建自定义语音气泡工具提示,根据每种情况调整/放置其箭头/指针

我有一个 WPF 语音气泡工具提示,运行良好。 <Setter Property="OverridesDefaultStyle" ...</desc> <question vote="0"> <p>我有一个 WPF 语音气泡工具提示,运行良好。</p> <pre><code>&lt;Style x:Key=&#34;{x:Type ToolTip}&#34; TargetType=&#34;ToolTip&#34;&gt; &lt;Setter Property=&#34;OverridesDefaultStyle&#34; Value=&#34;true&#34; /&gt; &lt;Setter Property=&#34;HorizontalOffset&#34; Value=&#34;1&#34; /&gt; &lt;Setter Property=&#34;VerticalOffset&#34; Value=&#34;1&#34; /&gt; &lt;Setter Property=&#34;Background&#34; Value=&#34;White&#34; /&gt; &lt;Setter Property=&#34;Foreground&#34; Value=&#34;Black&#34; /&gt; &lt;Setter Property=&#34;FontSize&#34; Value=&#34;12&#34; /&gt; &lt;Setter Property=&#34;FontFamily&#34; Value=&#34;Segoe UI&#34; /&gt; &lt;Setter Property=&#34;DataContext&#34; Value=&#34;{Binding Path=PlacementTarget.DataContext, RelativeSource={x:Static RelativeSource.Self}}&#34;/&gt; &lt;Setter Property=&#34;Template&#34;&gt; &lt;Setter.Value&gt; &lt;ControlTemplate TargetType=&#34;ToolTip&#34;&gt; &lt;Canvas Width=&#34;225&#34; Height=&#34;131&#34;&gt; &lt;Path x:Name=&#34;Container&#34; Canvas.Left=&#34;0&#34; Canvas.Top=&#34;0&#34; Margin=&#34;0&#34; Data=&#34;M8,7.41 L15.415,0 L22.83,7.41 L224,7.41 L224,130 L0,130 L0,7.41 L8,7.41&#34; Fill=&#34;{TemplateBinding Background}&#34; Stroke=&#34;Gray&#34;&gt; &lt;Path.Effect&gt; &lt;DropShadowEffect BlurRadius=&#34;10&#34; Opacity=&#34;0.5&#34; ShadowDepth=&#34;4&#34; /&gt; &lt;/Path.Effect&gt; &lt;/Path&gt; &lt;TextBlock Canvas.Left=&#34;10&#34; Canvas.Top=&#34;10&#34; Width=&#34;100&#34; Height=&#34;65&#34; Text=&#34;{TemplateBinding Content}&#34; TextWrapping=&#34;WrapWithOverflow&#34; /&gt; &lt;/Canvas&gt; &lt;/ControlTemplate&gt; &lt;/Setter.Value&gt; &lt;/Setter&gt; &lt;/Style&gt; </code></pre> <p>上述方法的问题是,无论情况如何,语音气泡工具提示(路径)的箭头/指针始终放置在相同的位置,我希望它适应情况并使用以下之一(以上样式实现箭头位于左上角,下面屏幕截图中的第一个工具提示):</p> <p><a href="https://i.stack.imgur.com/T2MdB.png" target="_blank"><img src="https://cdn.imgupio.com/i/AWkuc3RhY2suaW1ndXIuY29tL1QyTWRCLnBuZw==" alt=""/></a></p> <p>我该怎么做?可以吗?</p> </question> <answer tick="false" vote="1"> <p>这是此任务的完整代码:</p> <pre><code>using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace Decorators { public enum Position { None, Top, Bottom, RightSide, LeftSide, } public enum SpecificPosition { None, LeftOrTop = 25, Center = 50, RightOrBottom = 75, } internal class BubbleTextDecorator : Decorator { #region DependencyProperties public static readonly DependencyProperty VerticalMarginProperty = DependencyProperty.Register(&#34;VerticalMargin&#34;, typeof(double), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)); public double VerticalMargin { get { return (double)GetValue(VerticalMarginProperty); } set { SetValue(VerticalMarginProperty, value); } } public static readonly DependencyProperty HorizontalMarginProperty = DependencyProperty.Register(&#34;HorizontalMargin&#34;, typeof(double), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)); public double HorizontalMargin { get { return (double)GetValue(HorizontalMarginProperty); } set { SetValue(HorizontalMarginProperty, value); } } public static readonly DependencyProperty PointerPositionProperty = DependencyProperty.Register(&#34;PointerPosition&#34;, typeof(Position), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(Position.None, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); public Position PointerPosition { get { return (Position)GetValue(PointerPositionProperty); } set { SetValue(PointerPositionProperty, value); } } public static readonly DependencyProperty AlignmentPositionProperty = DependencyProperty.Register(&#34;AlignmentPosition&#34;, typeof(SpecificPosition), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(SpecificPosition.None, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); public SpecificPosition AlignmentPosition { get { return (SpecificPosition)GetValue(AlignmentPositionProperty); } set { SetValue(AlignmentPositionProperty, value); } } public static readonly DependencyProperty PointerHeightProperty = DependencyProperty.Register(&#34;PointerHeight&#34;, typeof(double), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)); public double PointerHeight { get { return (double)GetValue(PointerHeightProperty); } set { SetValue(PointerHeightProperty, value); } } public static readonly DependencyProperty PointerWidthProperty = DependencyProperty.Register(&#34;PointerWidth&#34;, typeof(double), typeof(BubbleTextDecorator), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender)); public double PointerWidth { get { return (double)GetValue(PointerWidthProperty); } set { SetValue(PointerWidthProperty, value); } } #endregion protected override Size ArrangeOverride(Size arrangeSize) { Size desiredSize = base.ArrangeOverride(arrangeSize); if (Child != null) { switch (PointerPosition) { case Position.Top: Child.Arrange(new Rect(new Point(0.0, PointerHeight), new Point(desiredSize.Width, desiredSize.Height))); break; case Position.Bottom: Child.Arrange(new Rect(new Point(0.0, 0.0), new Point(desiredSize.Width, desiredSize.Height - PointerHeight))); break; case Position.LeftSide: Child.Arrange(new Rect(new Point(PointerHeight, 0.0), new Point(desiredSize.Width, desiredSize.Height))); break; case Position.RightSide: Child.Arrange(new Rect(new Point(0.0, 0.0), new Point(desiredSize.Width - PointerHeight, desiredSize.Height))); break; } } return arrangeSize; } protected override Size MeasureOverride(Size constraint) { Size desiredSize = base.MeasureOverride(constraint); Size size = (PointerPosition == Position.Top || PointerPosition == Position.Bottom) ? new Size(desiredSize.Width + (HorizontalMargin * 2), desiredSize.Height + (VerticalMargin * 2) + PointerHeight) : new Size(desiredSize.Width + (HorizontalMargin * 2) + PointerHeight, desiredSize.Height + (VerticalMargin * 2)); return size; } protected override void OnRender(DrawingContext drawingContext) { Brush renderBrush = Brushes.Transparent; Pen renderPen = new Pen(Brushes.Black, 1); StreamGeometry geom = new StreamGeometry(); switch (PointerPosition) { case Position.Top: DrawTop(geom); break; case Position.Bottom: DrawBottom(geom); break; case Position.RightSide: DrawRight(geom); break; case Position.LeftSide: DrawLeft(geom); break; } // Some arbitrary drawing implements. drawingContext.DrawGeometry(renderBrush, renderPen, geom); } private void DrawLeft(StreamGeometry geom) { using (StreamGeometryContext ctx = geom.Open()) { ctx.BeginFigure( new Point(PointerHeight, 0.0), true, true); ctx.LineTo( new Point(ActualWidth, 0.0), true, false); ctx.LineTo( new Point(ActualWidth, ActualHeight), true, false); ctx.LineTo( new Point(PointerHeight, ActualHeight), true, false); ctx.LineTo( new Point(PointerHeight, (ActualHeight * (double)AlignmentPosition / 100) + (PointerWidth / 2)), true, false); ctx.LineTo( new Point(0.0, ActualHeight * (double)AlignmentPosition / 100), true, false); ctx.LineTo( new Point(PointerHeight, (ActualHeight * (double)AlignmentPosition / 100) - (PointerWidth / 2)), true, false); ctx.LineTo( new Point(PointerHeight, 0.0), true, false); } } private void DrawRight(StreamGeometry geom) { using (StreamGeometryContext ctx = geom.Open()) { ctx.BeginFigure( new Point(0.0, 0.0), true, true); ctx.LineTo( new Point(ActualWidth - PointerHeight, 0.0), true, false); ctx.LineTo( new Point(ActualWidth - PointerHeight, (ActualHeight * (double)AlignmentPosition / 100) - (PointerWidth / 2)), true, false); ctx.LineTo( new Point(ActualWidth, ActualHeight * (double)AlignmentPosition / 100), true, false); ctx.LineTo( new Point(ActualWidth - PointerHeight, (ActualHeight * (double)AlignmentPosition / 100) + (PointerWidth / 2)), true, false); ctx.LineTo( new Point(ActualWidth - PointerHeight, ActualHeight), true, false); ctx.LineTo( new Point(0.0, ActualHeight), true, false); ctx.LineTo( new Point(0.0, 0.0), true, false); } } private void DrawBottom(StreamGeometry geom) { using (StreamGeometryContext ctx = geom.Open()) { ctx.BeginFigure( new Point(0.0, 0.0), true, true); ctx.LineTo( new Point(ActualWidth, 0.0), true, false); ctx.LineTo( new Point(ActualWidth, ActualHeight - PointerHeight), true, false); ctx.LineTo( new Point((ActualWidth * (double)AlignmentPosition / 100) + (PointerWidth / 2), ActualHeight - PointerHeight), true, false); ctx.LineTo( new Point(ActualWidth * (double)AlignmentPosition / 100, ActualHeight), true, false); ctx.LineTo( new Point((ActualWidth * (double)AlignmentPosition / 100) - (PointerWidth / 2), ActualHeight - PointerHeight), true, false); ctx.LineTo( new Point(0.0, ActualHeight - PointerHeight), true, false); ctx.LineTo( new Point(0.0, 0.0), true, false); } } private void DrawTop(StreamGeometry geom) { using (StreamGeometryContext ctx = geom.Open()) { ctx.BeginFigure( new Point(0.0, PointerHeight), true, true); ctx.LineTo( new Point((ActualWidth * (double)AlignmentPosition / 100) - (PointerWidth / 2), PointerHeight), true, false); ctx.LineTo( new Point(ActualWidth * (double)AlignmentPosition / 100, 0.0), true, false); ctx.LineTo( new Point((ActualWidth * (double)AlignmentPosition / 100) + (PointerWidth / 2), PointerHeight), true, false); ctx.LineTo( new Point(ActualWidth, PointerHeight), true, false); ctx.LineTo( new Point(ActualWidth, ActualHeight), true, false); ctx.LineTo( new Point(0.0, ActualHeight), true, false); ctx.LineTo( new Point(0.0, PointerHeight), true, false); } } } } </code></pre> <p>这就是你如何使用它:</p> <pre><code>&lt;localdecorators:BubbleTextDecorator PointerHeight=&#34;10&#34; PointerWidth=&#34;20&#34; PointerPosition=&#34;LeftSide&#34; AlignmentPosition=&#34;Center&#34; VerticalMargin=&#34;30&#34; HorizontalMargin=&#34;30&#34; HorizontalAlignment=&#34;Left&#34;&gt; &lt;TextBlock Text=&#34;this&#34; HorizontalAlignment=&#34;Center&#34; VerticalAlignment=&#34;Center&#34;/&gt; &lt;/localdecorators:BubbleTextDecorator&gt; </code></pre> <p><a href="https://i.stack.imgur.com/0ycsH.png" target="_blank"><img src="https://cdn.imgupio.com/i/AWkuc3RhY2suaW1ndXIuY29tLzB5Y3NILnBuZw==" alt=""/></a></p> </answer> <answer tick="false" vote="0"> <p>目前我正在努力解决同样的问题。 您已经有解决这个问题的方法了吗?</p> <p>致以诚挚的问候</p> </answer> <answer tick="false" vote="-1"> <p>这是创建Decorator的典型案例。我曾经围绕文本制作了一个可定制的 ArrowBorder。你需要继承Decorator类。</p> <pre><code>internal class ArrowBorderDecorator : Decorator </code></pre> <p>然后你需要一些 DependencyProperties 以便于自定义。 在我的例子中,这是 <pre><code>ArrowTipToArrowTriangleBaseDistance</code></pre> 属性,这意味着箭头应该有多“尖”。在你的例子中,气泡文本箭头应该在哪里。</p> <pre><code> public static readonly DependencyProperty ArrowTipToArrowTriangleBaseDistanceProperty = DependencyProperty.Register(&#34;ArrowTipToArrowTriangleBaseDistance&#34;, typeof(double), typeof(ArrowBorderDecorator), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)); public double ArrowTipToArrowTriangleBaseDistance { get { return (double)GetValue(ArrowTipToArrowTriangleBaseDistanceProperty); } set { SetValue(ArrowTipToArrowTriangleBaseDistanceProperty, value); } } </code></pre> <p>然后您需要重写 <pre><code>ArrangeOverride</code></pre>、<pre><code>MeasureOverride</code></pre> 和 <pre><code>OnRender</code></pre> 方法。前两个来自 Decorator 类,第三个来自 UIElement 类。</p> <p>这里有一个很好的<a href="https://stackoverflow.com/questions/66818340/measureoverride-and-arrangeoverride-what-is-really-availablesize-desiredsize">链接</a>来理解前两个。 在 <pre><code>OnRender</code></pre> 中,您有一个 DrawingContext,可以使用 DependenyProperties 绘制所需的形状。</p> <p>在这些之后,您可以像这样在 xaml 中使用装饰器:</p> <pre><code>&lt;localdecorators:ArrowBorderDecorator ArrowBaseHalfSegment=&#34;0&#34; FillColor=&#34;{DynamicResource MahApps.Brushes.Accent3}&#34; StrokeColor=&#34;{DynamicResource MahApps.Brushes.ThemeForeground}&#34; ArrowBorderThickness=&#34;1&#34; ArrowTipToArrowTriangleBaseDistance=&#34;10&#34;&gt; &lt;TextBlock Text=&#34;{Binding Path=Title}&#34; Foreground=&#34;{DynamicResource MahApps.Brushes.IdealForeground}&#34; Padding=&#34;10 1 10 1&#34; VerticalAlignment=&#34;Center&#34; FontWeight=&#34;Bold&#34;&gt; &lt;/TextBlock&gt;&lt;/localdecorators:ArrowBorderDecorator&gt; </code></pre> <p><a href="https://i.stack.imgur.com/bETwO.png" target="_blank"><img src="https://cdn.imgupio.com/i/AWkuc3RhY2suaW1ndXIuY29tL2JFVHdPLnBuZw==" alt=""/></a> <a href="https://i.stack.imgur.com/njfyp.png" target="_blank"><img src="https://cdn.imgupio.com/i/AWkuc3RhY2suaW1ndXIuY29tL25qZnlwLnBuZw==" alt=""/></a></p> </answer> </body></html>

回答 0 投票 0

© www.soinside.com 2019 - 2024. All rights reserved.