2012-05-24 74 views
0

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

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

没有太多的文档这一点,我怕我在做一些愚蠢的或不必要的,如强制刷新/重绘每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)); 
    } 
} 

回答

3

你可以做到这一点很容易,没有任何附加属性。使用时只需将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> 

与填充用你的控制:

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

谢谢您的回答!这是一个很好的建议,但并不真正给我我想要的答案。我更了解如何正确使用** OnRenderSizeChanged **并更新其他元素绑定到的属性。 – Reyhn

+0

好吧,那么你可以通过用OnPropertyChanged函数替换对OnPropertyChanged的四个调用来提高性能,每个调用都带有一个属性名称参数,方法是使用null参数或空字符串对OnPropertyChanged进行一次调用。这会通知所有属性一次改变。 – Clemens