【问题标题】:WPF custom Control with custom drawing and ActualWidth带有自定义绘图和 ActualWidth 的 WPF 自定义控件
【发布时间】:2012-05-24 10:05:45
【问题描述】:

我正在尝试使用自己的绘图逻辑创建一个自定义控件(源自 Control)。该控件只是从控件的左上角到右下角绘制一条对角线。此逻辑基于控件的 ActualWidthActualHeight,它们仅在呈现控件 (AFAIK) 时可用。

我的问题是,有效地进行自定义绘图的正确方法是什么?

这方面的文档不多,恐怕我在做一些愚蠢或不必要的事情,比如每次触发 OnPropertyChanged 时都强制刷新/重绘...

这是控件的模板:

<Style TargetType="{x:Type local:MyCustomControl}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
          <Canvas>
            <Line x:Name="PART_Diagonal"
                  Y1="{Binding Path=DiagonalTop}"
                  Y2="{Binding Path=DiagonalBottom}"
                  X1="{Binding Path=DiagonalLeft}"
                  X2="{Binding Path=DiagonalRight}"
                  Stroke="Red" />
          </Canvas>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

这是逻辑:

public class MyCustomControl : Control, INotifyPropertyChanged
{
  static MyCustomControl()
  {
    DefaultStyleKeyProperty.OverrideMetadata( typeof( MyCustomControl ), new FrameworkPropertyMetadata( typeof( MyCustomControl ) ) );
  }

  public MyCustomControl()
  {
    DataContext = this;
  }

  protected override void OnRenderSizeChanged( SizeChangedInfo sizeInfo )
  {
    base.OnRenderSizeChanged( sizeInfo );

    var margin = 25d;

// These calculations are based on the control's current size.
    DiagonalTop = margin;
    DiagonalBottom = ActualHeight - margin;
    DiagonalLeft = margin;
    DiagonalRight = ActualWidth - margin;

// Is this forcing redraws (i.e. invalidating the layout)?
    OnPropertyChanged( "DiagonalTop" );
    OnPropertyChanged( "DiagonalBottom" );
    OnPropertyChanged( "DiagonalLeft" );
    OnPropertyChanged( "DiagonalRight" );
  }

  public double DiagonalTop { get; private set; }
  public double DiagonalBottom{ get; private set; }
  public double DiagonalLeft { get; private set; }
  public double DiagonalRight { get; private set; }

  public event PropertyChangedEventHandler PropertyChanged;
  protected void OnPropertyChanged(string propertyname)
  {
    if (PropertyChanged != null)
      PropertyChanged.Invoke( this, new PropertyChangedEventArgs( propertyname ) );
  }
}

【问题讨论】:

    标签: wpf xaml controls drawingcontext actualwidth


    【解决方案1】:

    您可以更轻松地完成此操作,而无需任何其他属性。只需使用 Padding 属性作为内部间距:

    <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
        <Border Background="{TemplateBinding Background}" 
                BorderBrush="{TemplateBinding BorderBrush}" 
                BorderThickness="{TemplateBinding BorderThickness}"
                Padding="{TemplateBinding Padding}">
            <Canvas Name="DrawingCanvas">
                <Line X1="0" X2="{Binding ActualWidth, ElementName=DrawingCanvas}" 
                      Y1="0" Y2="{Binding ActualHeight, ElementName=DrawingCanvas}" 
                      Stroke="Red" />
            </Canvas>
        </Border>
    </ControlTemplate>
    

    通过 Padding 使用您的控件:

    <local:MyCustomControl Padding="25" ... />
    

    【讨论】:

    • 感谢您的回答!这是一个很好的建议,但并没有真正给我想要的答案。我更感兴趣的是了解如何正确使用 OnRenderSizeChanged 并更新其他元素绑定到的属性。
    • 好的,那么您可以通过使用空参数或空字符串对 OnPropertyChanged 的​​单个调用替换对 OnPropertyChanged 的​​四个调用(每个调用都带有一个属性名称参数)来提高性能。这将通知所有属性都已立即更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多