You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF自定义T型Shape的MeasureOverride无限值布局异常求助

解决WPF自定义T型Shape的布局自适应与无限约束报错问题

问题根源

直接返回constraint作为MeasureOverride的结果,当父容器传递无限尺寸约束(如Grid的Auto行、无明确尺寸的控件模板)时,会触发InvalidOperationException——WPF不允许控件的DesiredSize为无限值。同时需要保证控件能自适应父容器尺寸,且垂直线始终居中。

解决方案

通过合理处理MeasureOverride的无限约束,并重写ArrangeOverride强制占满分配空间,同时优化几何图形的构建方式来解决问题:

1. 处理MeasureOverride中的无限约束

在MeasureOverride中,当约束尺寸为无限时返回一个默认的合理尺寸,否则返回父容器的约束,避免报错的同时保留自适应能力:

Protected Overrides Function MeasureOverride(constraint As Size) As Size
    ' 当约束为无限时返回默认尺寸,否则使用父容器约束
    Dim desiredWidth = If(Double.IsPositiveInfinity(constraint.Width), 100.0, constraint.Width)
    Dim desiredHeight = If(Double.IsPositiveInfinity(constraint.Height), 100.0, constraint.Height)
    Return New Size(desiredWidth, desiredHeight)
End Function

2. 重写ArrangeOverride强制占满空间

确保控件实际占用父容器分配的全部空间,让ActualWidth和ActualHeight正确反映当前尺寸,保证垂直线居中:

Protected Overrides Function ArrangeOverride(finalSize As Size) As Size
    ' 强制使用父容器分配的全部空间
    MyBase.ArrangeOverride(finalSize)
    Return finalSize
End Function

3. 优化DefiningGeometry的实现

使用StreamGeometry替代Geometry.Parse,提升性能且避免字符串格式化的文化差异问题:

Protected Overrides ReadOnly Property DefiningGeometry As Geometry
    Get
        Dim geometry As New StreamGeometry()
        Using ctx As StreamGeometryContext = geometry.Open()
            ' 绘制顶部水平线
            ctx.BeginFigure(New Point(0, 0), False, False)
            ctx.LineTo(New Point(ActualWidth, 0), True, False)
            
            ' 绘制居中垂直线
            Dim centerX = ActualWidth / 2
            ctx.BeginFigure(New Point(centerX, 0), False, False)
            ctx.LineTo(New Point(centerX, ActualHeight), True, False)
        End Using
        geometry.Freeze() ' 冻结几何图形以提升性能
        Return geometry
    End Get
End Property

完整代码

Imports System.Windows
Imports System.Windows.Media

Public Class MyShape
    Inherits Shape

    Public Sub New()
        MyBase.New()
    End Sub

    Protected Overrides Function MeasureOverride(constraint As Size) As Size
        Dim desiredWidth = If(Double.IsPositiveInfinity(constraint.Width), 100.0, constraint.Width)
        Dim desiredHeight = If(Double.IsPositiveInfinity(constraint.Height), 100.0, constraint.Height)
        Return New Size(desiredWidth, desiredHeight)
    End Function

    Protected Overrides Function ArrangeOverride(finalSize As Size) As Size
        MyBase.ArrangeOverride(finalSize)
        Return finalSize
    End Function

    Protected Overrides ReadOnly Property DefiningGeometry As Geometry
        Get
            Dim geometry As New StreamGeometry()
            Using ctx As StreamGeometryContext = geometry.Open()
                ' 顶部水平线
                ctx.BeginFigure(New Point(0, 0), False, False)
                ctx.LineTo(New Point(ActualWidth, 0), True, False)
                
                ' 居中垂直线
                Dim centerX = ActualWidth / 2
                ctx.BeginFigure(New Point(centerX, 0), False, False)
                ctx.LineTo(New Point(centerX, ActualHeight), True, False)
            End Using
            geometry.Freeze()
            Return geometry
        End Get
    End Property
End Class

关键说明

  • MeasureOverride:通过默认尺寸兜底无限约束场景,既符合WPF布局规则,又能在有明确约束时自适应父容器。
  • ArrangeOverride:强制控件占满分配空间,确保ActualWidth/ActualHeight准确反映当前尺寸,保证垂直线始终居中。
  • StreamGeometry:相比字符串解析的几何图形,性能更高且无需处理格式化问题,适合自定义Shape的几何构建。

内容的提问来源于stack exchange,提问作者Nostromo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 23:31:03