2017-01-27 150 views
0

我正在使用C#-WPF。重新評估UserControl中的屬性

我做了我自己的UserControl,一個簡單的十字。通過座標,我可以在圖像上繪製一個X.

參數爲:

  • CenterPoint的:中心的橫
  • 前景:色爲橫
  • 厚度:厚度爲十字

我Cross.xaml:

<UserControl x:Name="userControl" 
      x:Class="Project.Cross"> 
    <Grid> 
     <Line Stroke="{Binding Foreground, ElementName=userControl}" 
       StrokeThickness="{Binding Thickness, ElementName=userControl}" 
       X1="{Binding X1, ElementName=userControl, Mode=OneWay}" 
       X2="{Binding X2, ElementName=userControl, Mode=OneWay}" 
       Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}" 
       Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}" /> 

     <Line Stroke="{Binding Foreground, ElementName=userControl}" 
       StrokeThickness="{Binding Thickness, ElementName=userControl}" 
       X1="{Binding X2, ElementName=userControl, Mode=OneWay}" 
       X2="{Binding X1, ElementName=userControl, Mode=OneWay}" 
       Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}" 
       Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}"/> 
    </Grid> 
</UserControl> 

我Cross.xaml.cs:

public partial class Cross : UserControl 
{ 
    public Cross() 
    { 
     InitializeComponent(); 
    } 

    public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint", 
     typeof(PointF), typeof(Cross), 
     new PropertyMetadata(default(PointF))); 

    public PointF CenterPoint 
    { 
     get { return (PointF)GetValue(CenterPointProperty); } 
     set { SetValue(CenterPointProperty, value); } 
    } 

    public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register("Thickness", 
     typeof(int), typeof(Cross), 
     new PropertyMetadata(2)); 

    public int Thickness 
    { 
     get { return (int)GetValue(ThicknessProperty); } 
     set { SetValue(ThicknessProperty, value); } 
    } 

    public float X1 
    { 
     get 
     { 
      return (float)(CenterPoint.X - (Width/2)); 
     } 
    } 
    public float X2 
    { 
     get 
     { 
      return (float)(CenterPoint.X + (Width/2)); 
     } 
    } 
    public float Y1 
    { 
     get 
     { 
      return (float)(CenterPoint.Y - (Height/2)); 
     } 
    } 
    public float Y2 
    { 
     get 
     { 
      return (float)(CenterPoint.Y + (Height/2)); 
     } 
    } 
} 

我可以把它想:

<local:Cross CenterPoint="{Binding Point}" Thickness="8" Foreground="Yellow" Height="40" Width="40"/> 

我有一個問題,則不會顯示在十字架上。我添加了斷點,看起來X1,X2,...在更改CenterPoint時不會刷新。我如何強制C#重新評估這些值? (希望這解決了我的問題)

謝謝

+0

您可以顯示本地的xaml:跨定義?例如它包含什麼? –

+0

我不明白你的問題。我展示了Cross.xaml文件,我在本地命名空間中定義了UserControl'Cross'。 –

+0

我只是想知道爲什麼不根據用戶控件的寬度和高度繪製交叉爲固定大小,然後通過設置其相對於目標對象的位置來移動該對象。所以我想知道你在畫什麼。 –

回答

1

MM8的方法將更新X1等方面的工作,但也有需要解決的另外的問題使控制工作。

我使用的是另一種方式來更新協調性:讓X1等進入read-only dependency properties,和你的用戶控件更新它們的時候CenterPoint變化和當控件的大小變化。

我也改變了你的WinForms PointF到WPF的System.Windows.Point,它使用doubleXY,我已經改變了Thicknessfloat爲好,因爲WPF使用float線路厚度,你不妨充分優點。

我更新的SizeChanged事件,這是至關重要的座標,否則,座標屬性將只在控件創建時的實際大小爲0×0,和WidthHeightNaN設置。

最後,你應該使用ActualWidthActualHeight,這是更新的「活」不像HeightWidth,這是設計時的屬性值。如果你給它一個固定的WidthHeight,效果將是相同的;如果需要的話,使用ActualWidthActualHeight可以拉伸以適應容器。

public partial class Cross : UserControl 
{ 
    public Cross() 
    { 
     InitializeComponent(); 

     SizeChanged += Cross_SizeChanged; 
    } 

    private void Cross_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     UpdateXYProperties(); 
    } 

    protected void UpdateXYProperties() 
    { 
     X1 = (float)(CenterPoint.X - (ActualWidth/2)); 
     X2 = (float)(CenterPoint.X + (ActualWidth/2)); 
     Y1 = (float)(CenterPoint.Y - (ActualHeight/2)); 
     Y2 = (float)(CenterPoint.Y + (ActualHeight/2)); 
    } 

    public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register(nameof(CenterPoint), 
     typeof(Point), typeof(Cross), 
     new PropertyMetadata(default(Point), CenterPoint_PropertyChanged)); 

    private static void CenterPoint_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     ((Cross)obj).UpdateXYProperties(); 
    } 

    public Point CenterPoint 
    { 
     get { return (Point)GetValue(CenterPointProperty); } 
     set { SetValue(CenterPointProperty, value); } 
    } 

    public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register(nameof(Thickness), 
     typeof(float), typeof(Cross), 
     new PropertyMetadata(2.0F)); 

    public float Thickness 
    { 
     get { return (float)GetValue(ThicknessProperty); } 
     set { SetValue(ThicknessProperty, value); } 
    } 

    #region Read-Only Properties 
    #region X1 Property 
    public float X1 
    { 
     get { return (float)GetValue(X1Property); } 
     protected set { SetValue(X1PropertyKey, value); } 
    } 

    internal static readonly DependencyPropertyKey X1PropertyKey = 
     DependencyProperty.RegisterReadOnly("X1", typeof(float), typeof(Cross), 
      new PropertyMetadata(0.0F)); 

    public static readonly DependencyProperty X1Property = X1PropertyKey.DependencyProperty; 
    #endregion X1 Property 

    #region X2 Property 
    public float X2 
    { 
     get { return (float)GetValue(X2Property); } 
     protected set { SetValue(X2PropertyKey, value); } 
    } 

    internal static readonly DependencyPropertyKey X2PropertyKey = 
     DependencyProperty.RegisterReadOnly("X2", typeof(float), typeof(Cross), 
      new PropertyMetadata(0.0F)); 

    public static readonly DependencyProperty X2Property = X2PropertyKey.DependencyProperty; 
    #endregion X2 Property 

    #region Y1 Property 
    public float Y1 
    { 
     get { return (float)GetValue(Y1Property); } 
     protected set { SetValue(Y1PropertyKey, value); } 
    } 

    internal static readonly DependencyPropertyKey Y1PropertyKey = 
     DependencyProperty.RegisterReadOnly("Y1", typeof(float), typeof(Cross), 
      new PropertyMetadata(0.0F)); 

    public static readonly DependencyProperty Y1Property = Y1PropertyKey.DependencyProperty; 
    #endregion Y1 Property 

    #region Y2 Property 
    public float Y2 
    { 
     get { return (float)GetValue(Y2Property); } 
     protected set { SetValue(Y2PropertyKey, value); } 
    } 

    internal static readonly DependencyPropertyKey Y2PropertyKey = 
     DependencyProperty.RegisterReadOnly("Y2", typeof(float), typeof(Cross), 
      new PropertyMetadata(0.0F)); 

    public static readonly DependencyProperty Y2Property = Y2PropertyKey.DependencyProperty; 
    #endregion Y2 Property 
    #endregion Read-Only Properties 
} 

最後,你並不需要明確地讓你的綁定Mode=OneWay,因爲Line.X1等無法更新綁定源(那是你自己的X1等。在這種情況下),所以他們已經默認爲OneWay

<Grid> 
    <Line 
     Stroke="{Binding Foreground, ElementName=userControl}" 
     StrokeThickness="{Binding Thickness, ElementName=userControl}" 
     X1="{Binding X1, ElementName=userControl}" 
     X2="{Binding X2, ElementName=userControl}" 
     Y1="{Binding Y1, ElementName=userControl}" 
     Y2="{Binding Y2, ElementName=userControl}" 
     /> 

    <Line 
     Stroke="{Binding Foreground, ElementName=userControl}" 
     StrokeThickness="{Binding Thickness, ElementName=userControl}" 
     X1="{Binding X2, ElementName=userControl}" 
     X2="{Binding X1, ElementName=userControl}" 
     Y1="{Binding Y1, ElementName=userControl}" 
     Y2="{Binding Y2, ElementName=userControl}" 
     /> 
</Grid> 

最後,幾乎可以肯定至少:在CenterPoint設計的效果,如果它不是控制的實際中心,以抵消控制邊界的交叉之外。如果這是您的意圖,請不要閱讀本段的其餘部分。如果這不是你的意圖,你可以重寫UpdateXYProperties()如下而失去CenterPoint屬性:

protected void UpdateXYProperties() 
{ 
    X1 = 0; 
    X2 = (float)ActualWidth; 
    Y1 = 0; 
    Y2 = (float)ActualHeight; 
} 

但是,這是給你和聖安德魯斯。

+0

我試過這個解決方案,但我可以運行我的應用程序。有一個XmlParseException類似於「Cross的構造函數引發異常」。 –

+0

@ A.Pissicat我可以看到產生該異常的實際代碼嗎?我沒有這樣做。 –

+0

我發現了錯誤。 'PropertyMetadata(0.0)'沒有被認爲有一個浮點數。我用'PropertyMetadata(default(float))'替換了這些指令,我沒有錯誤。我仍然看不到我的十字架,但我可以運行我的項目。我正在尋找他們爲什麼不顯示。 –

2

如果你希望綁定到X1,X2,Y1和Y2只讀屬性得到刷新時中心點依賴屬性被設置爲一個新的值UserControl應該實現INotifyPropertyChanged接口。然後,您可以註冊的依賴屬性PropertyChangedCallback,提高爲只讀屬性PropertyChanged事件:

public partial class Cross : UserControl, INotifyPropertyChanged 
{ 
    public Cross() 
    { 
     InitializeComponent(); 
    } 

    public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint", 
     typeof(PointF), typeof(Cross), 
     new PropertyMetadata(default(PointF), new PropertyChangedCallback(OnCenterPointUpdated)))); 

    private static void OnCenterPointUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     Cross cross = d as Cross; 
     cross.NotifyPropertyChanged("X1"); 
     cross.NotifyPropertyChanged("X2"); 
     cross.NotifyPropertyChanged("Y1"); 
     cross.NotifyPropertyChanged("Y2"); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    ... 
}