2017-01-27 4 views
0

Ich arbeite in C# -WPF.Eigenschaft in UserControl neu bewerten

Ich habe mein eigenes UserControl, ein einfaches Kreuz. Mit Koordinaten kann ich ein X auf ein Bild zeichnen.

Parameter sind:

  • Centerpoint: Zentrum für die Quer
  • Vordergrund: Farbe für das Quer
  • Dicke: Dicke für die Quer

Mein 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> 

Mein 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)); 
     } 
    } 
} 

Ich kann es nennen mag:

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

Ich habe ein Problem, das Kreuz wird nicht angezeigt. Ich habe Haltepunkte hinzugefügt, es scheint, dass die Werte X1, X2, ... nicht aktualisiert werden, wenn ich den CenterPoint ändere. Wie kann ich C# erzwingen, diese Werte neu zu bewerten? (Hoffen, das ist mein Problem zu lösen)

Danke

+0

Können Sie das Xaml zeigen, in dem das local: Cross definiert ist? ZB was ist darin enthalten? –

+0

Ich verstehe deine Frage nicht. Ich habe die Datei Cross.xaml gezeigt, wo ich das UserControl 'Cross' in meinem lokalen Namensraum definiere. –

+0

Ich wundere mich nur, warum Sie nicht das Kreuz als eine feste Größe basierend auf Breite und Höhe des Benutzersteuerelements zeichnen und dann das Objekt um das, was Sie gerade zeichnen, bewegen, indem Sie seine Position relativ zum Zielobjekt festlegen. Also habe ich mich gefragt, was du da draus machst. –

Antwort

1

mm8 Methode zur Aktualisierung X1 usw. funktionieren wird, aber es gibt weitere Probleme, die gelöst werden müssen mach die Kontrolle funktionieren.

Ich verwende einen alternativen Weg, um die Koordinateneigenschaften zu aktualisieren: Machen Sie X1 usw. in read-only dependency properties und lassen Sie Ihre Benutzersteuerung sie aktualisieren, wenn sich CenterPoint ändert und wenn sich die Größe des Steuerelements ändert.

Ich habe mich verändert auch deine winforms PointF auf einen System.Windows.Point WPF, die double für X und Y verwendet, und ich habe Thickness zu float auch geändert, weil WPF float für Linienstärke verwendet, und Sie auch voll in Anspruch nehmen Vorteil.

ich die Aktualisierung der Koordinaten auf dem SizeChanged Ereignis, das, da sonst kritisch ist, werden die Koordinaten Eigenschaften nur auf Steuer Schöpfung gesetzt werden, wenn die tatsächliche Größe 0 x 0 ist, und Width und Height sind NaN.

Schließlich sollten Sie ActualWidth und ActualHeight verwenden, die „live“ im Gegensatz zu Height und Width aktualisiert werden, die Attributwerte Design-Zeit. Wenn Sie eine feste Width und Height geben, wird der Effekt gleich sein; Mit ActualWidth und ActualHeight kann es dehnen, um einen Behälter zu passen, wenn das gewünscht wird.

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 
} 

Schließlich brauchen Sie nicht explizit auf Ihre Bindungen Mode=OneWay zu machen, weil Line.X1 usw. können nicht die Bindungsquelle aktualisieren (das ist Ihre eigene X1 usw. in diesem Fall), und so sind sie bereits OneWay standardmäßig.

<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> 

Schließlich und mit ziemlicher Sicherheit least: Die Wirkung des CenterPoint Designs wird das Kreuz außerhalb der Kontrolle des Grenze zu versetzen, wenn es nicht das eigentliche Zentrum der Steuerung ist. Wenn das Ihre Absicht war, sollten Sie den Rest dieses Absatzes nicht lesen. Wenn das nicht Ihre Absicht war, konnte man UpdateXYProperties() wie folgt umschreiben und verlieren die CenterPoint Eigenschaft:

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

Aber das ist bis zu Ihnen und St. Andrew.

+0

Ich habe diese Lösung versucht, aber ich kann meine Anwendung ausführen. Es gibt eine XmlParseException mit etwas wie "Konstruktor für Kreuz hat eine Ausnahme ausgelöst". –

+0

@ A.Pissicat Kann ich Ihren tatsächlichen Code sehen, der diese Ausnahme erzeugt hat? Meins macht das nicht. –

+0

Ich habe den Fehler gefunden. 'PropertyMetadata (0.0)' wurde nicht als Float betrachtet. Ich habe diese Anweisung durch 'PropertyMetadata (default (float)) 'ersetzt und habe keinen Fehler. Ich kann mein Kreuz immer noch nicht sehen, aber ich kann mein Projekt leiten. Ich suche, warum sie nicht angezeigt werden. –

2

Wenn Sie die Bindungen an der X1 wollen, X2, Y1 und Y2 Nur-Lese-Eigenschaften aktualisiert zu erhalten, wenn die Centerpoint-Abhängigkeitseigenschaft auf einen neuen Wert gesetzt wird UserControl sollte die Schnittstelle INotifyPropertyChanged implementieren. Sie könnten dann ein PropertyChangedCallback für die Abhängigkeitseigenschaft registrieren und das PropertyChanged Ereignis für die Nur-Lese-Eigenschaften erhöhen:

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)); 
    } 

    ... 
} 
Verwandte Themen