UserControl定位理解

UserControl positioning understanding

我越来越接近对 System.Windows.Controls.UserControl 对象定位的理解:
默认情况下,它们没有相对于其容器的 X 或 Y 坐标,但可以使用所谓的“附加属性”添加一些坐标。
这种附加属性的典型示例是 Canvas.LeftCanvas.Top,这意味着,如果 UserControl 的容器是 Canvas,则以下情况发生(假设) 其左上点(伪代码):

UserControl_UpperLeft_Point.X = Canvas.Left
UserControl_UpperLeft_Point.Y = Canvas.Top

现在我想知道的是:

如果您想将控件放置在容器内,您应该遵循 WPF 方式。

水平和垂直对齐并设置边距,就是这样。

<Grid>
  <Grid.Resources>
    <Style TargetType="Border">
      <Setter Property="CornerRadius" Value="5" />
      <Setter Property="Width" Value="50" />
      <Setter Property="Height" Value="50" />
      <Setter Property="Background" Value="Red" />
      <Setter Property="TextElement.Foreground" Value="White" />
      <Setter Property="TextElement.FontWeight" Value="Bold" />
    </Style>
    <Style TargetType="TextBlock">
      <Setter Property="HorizontalAlignment" Value="Center" />
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="TextAlignment" Value="Center" />
    </Style>
  </Grid.Resources>

  <!--#region top-->
  <Border
    Margin="20,20,0,0"
    HorizontalAlignment="Left"
    VerticalAlignment="Top">
    <TextBlock>
      Top<LineBreak />
      Left</TextBlock>
  </Border>

  <Border
    Margin="0,20,0,0"
    HorizontalAlignment="Center"
    VerticalAlignment="Top">
    <TextBlock>
      Top<LineBreak />
      Center</TextBlock>
  </Border>

  <Border
    Margin="0,20,20,0"
    HorizontalAlignment="Right"
    VerticalAlignment="Top">
    <TextBlock>
      Top<LineBreak />
      Right</TextBlock>
  </Border>
  <!--#endregion-->

  <!--#region center-->
  <Border
    Margin="20,0,0,0"
    HorizontalAlignment="Left"
    VerticalAlignment="Center">
    <TextBlock>
      Center<LineBreak />
      Left</TextBlock>
  </Border>

  <Border
    Margin="0,0,0,0"
    HorizontalAlignment="Center"
    VerticalAlignment="Center">
    <TextBlock>
      Center<LineBreak />
      Center</TextBlock>
  </Border>

  <Border
    Margin="0,0,20,0"
    HorizontalAlignment="Right"
    VerticalAlignment="Center">
    <TextBlock>
      Center<LineBreak />
      Right</TextBlock>
  </Border>
  <!--#endregion-->

  <!--#region bottom-->
  <Border
    Margin="0,0,20,20"
    HorizontalAlignment="Right"
    VerticalAlignment="Bottom">
    <TextBlock>
      Bottom<LineBreak />
      Right</TextBlock>
  </Border>

  <Border
    Margin="0,0,0,20"
    HorizontalAlignment="Center"
    VerticalAlignment="Bottom">
    <TextBlock>
      Bottom<LineBreak />
      Center</TextBlock>
  </Border>

  <Border
    Margin="20,0,0,20"
    HorizontalAlignment="Left"
    VerticalAlignment="Bottom">
    <TextBlock>
      Bottom<LineBreak />
      Left</TextBlock>
  </Border>
  <!--#endregion-->

</Grid>

如果你想要 old 样式(从 WinForms 中知道你可以对齐它 HorizontalAlignemnt="Top"VerticalAlignment="Left" 并使用 LeftMarginTop 属性 设置旧学校 LeftTop.

Is my idea correct? Is it indeed the upper left corner which is used?

在这种情况下有效左上角,但实际上每个都是对齐的。此外,控件由 Canvas 对齐,它没有设置内部 X 或 Y 坐标。它们由特定于 Canvas 的附加属性给出,没有其他面板。 Canvas 在内部计算绘制 UserControl.

的矩形
  • Canvas.Left

    Gets or sets a value that represents the distance between the left side of an element and the left side of its parent Canvas.

  • Canvas.Top

    Gets or sets a value that represents the distance between the top of an element and the top of its parent Canvas.

同样重要的是要注意,附加属性有一个 priority

If you specify them, the attached properties Canvas.Top or Canvas.Left take priority over Canvas.Bottom or Canvas.Right.


What if I want to modify this behaviour, let's say into: [...]

您仍然需要分配附加属性,但之前计算表达式。

  • BindingMultiBinding 与自定义值转换器一起使用,以评估作为转换器参数绑定或传递的表达式,或与专用值转换器一起计算特定项。
  • 创建您自己的专用附加属性,在内部将计算值分配给 Canvas 个附加属性。

What if I want to position my UserControl, based on the upper right corner

改为设置 Canvas.TopCanvas.Right 附加属性。

<Canvas>
   <local:MyUserControl Canvas.Top="0" Canvas.Right="0" Width="50" Height="80"/>
</Canvas>

[...] or even the center?

A Canvas用于绝对定位。如果你想居中控制,Grid 可能是更好的选择。如果您仍想使用 Canvas 并且它是固定大小,只需自己计算中心坐标并相应地设置附加属性即可。如果它可以调整大小并且 UserControl 位置的位置需要对此做出响应,您可以执行以下操作之一。

  • Canvas周围放一个Grid,在之后放UserControl。它会出现在 Canvas 的顶部,并且会自动居中,即使在调整大小时也是如此。

    Grid>
       <Canvas>
          <Rectangle Canvas.Top="80" Canvas.Left="20" Fill="Black" Width="50" Height="50"/>
          <Rectangle Canvas.Top="300" Canvas.Left="230" Fill="Black" Width="100" Height="80"/>
       </Canvas>
       <local:MyUserControl Width="50" Height="80"/>
    </Grid>
    
  • 使用 Canvas 的绑定 ActualSize 来设置附加属性,实现自定义行为或与转换器的复杂绑定,我 不推荐.

我认为对于你的最后一个问题,询问 为什么 你需要这种行为,你想要实现什么 更有用。通常有更简单、更合适的解决方案。