2012-09-28 13 views
8

Das ist ganz einfach, von Code-behind zu tun:Wie ändere ich NUR den rechten (oder linken, oberen, unteren) Wert der Margin-Eigenschaft eines WPF-Steuerelements?

var button = new Button(); 
var margin = button.Margin; 
margin.Right = 10; 
button.Margin = margin; 

In XAML aber ich bin auf die folgende begrenzt:

<Button Margin="0,0,10,0" /> 

Das Problem dabei ist, dass ich jetzt habe möglicherweise die anderen Randwerte überschrieben (dh links, oben, unten), indem sie auf Null gesetzt werden.

Gibt es eine Möglichkeit, XAML wie folgt zu haben?

<Button MarginRight="10" /> 

Antwort

7

Eine angehängte Eigenschaft könnte verwendet werden. Tatsächlich ist dies genau der Zweck der angefügten Eigenschaften: Zugreifen auf Elternelementeigenschaften oder Hinzufügen zusätzlicher Funktionalität zu einem bestimmten Element.

Zum Beispiel definiert die folgende Klasse irgendwo in der Anwendung:

using System; 
using System.Windows; 
using System.Windows.Controls; 

namespace YourApp.AttachedProperties 
{ 
    public class MoreProps 
    { 
     public static readonly DependencyProperty MarginRightProperty = DependencyProperty.RegisterAttached(
      "MarginRight", 
      typeof(string), 
      typeof(MoreProps), 
      new UIPropertyMetadata(OnMarginRightPropertyChanged)); 

     public static string GetMarginRight(FrameworkElement element) 
     { 
      return (string)element.GetValue(MarginRightProperty); 
     } 

     public static void SetMarginRight(FrameworkElement element, string value) 
     { 
      element.SetValue(MarginRightProperty, value); 
     } 

     private static void OnMarginRightPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
     { 
      var element = obj as FrameworkElement; 

      if (element != null) 
      { 
       int value; 
       if (Int32.TryParse((string)args.NewValue, out value)) 
       { 
        var margin = element.Margin; 
        margin.Right = value; 
        element.Margin = margin; 
       } 
      } 
     } 
    } 
} 

Jetzt in Ihrem XAML alles, was Sie tun müssen, ist die folgende Namespace deklariert:

xmlns:ap="clr-namespace:YourApp.AttachedProperties" 

Und dann können Sie XAML schreiben wie die folgenden:

<Button ap:MoreProps.MarginRight="10" /> 



Alternativ können Sie auch eine angeschlossene Eigenschaft vermeiden, mit und stattdessen eine etwas längere XAML wie schreiben:

<Button>
        <Button.Margin>
                <Thickness Right="10" />
        </Button.Margin>
</Button>

+3

Das XAML am Ende ist das gleiche wie 'Margin =„0,0,10,0“', wie Sie überschreiben die vorhandene 'Thickness', wenn es ist ein. –

+1

@ H.B. Danke, ich hätte diesen letzten Teil testen sollen. Du hast recht. Der gesamte Rand wird neu zugewiesen und alle nicht angegebenen Werte werden auf den Standardwert zurückgesetzt. Ich habe die Antwort bearbeitet, um diesen Teil zu markieren. – bugged87

0

Sie sind falsch mit diesem Teil:

var button = new Button(); 
button.Margin.Right = 10; 

erro r CS1612: Kann nicht den Rückgabewert von ‚System.Windows.FrameworkElement.Margin‘ geändert werden, da es keine Variable ist

Ist schon nicht gültige Code, weil Margin ein struct zurück und ist somit ein Werttyp. Und weil es nicht von DependencyObject abgeleitet ist, funktionieren auch viele DataBinding-Tricks nicht.

Ich wollte nur eine richtige Erklärung geben, sonst würde ich sagen, Ihre erste Antwort ist so ziemlich der einzige Weg.

+0

@ dowhilefor Sie haben Recht mit dem Code-Behind-Teil. Tippfehler meinerseits. Ich habe meine Frage aktualisiert, um zu reflektieren, was ich eigentlich meinte. DataBinding funktioniert jedoch, da die MarginRight-Eigenschaft ein DependencyObject ist. Wenn der Eigenschaftswert über die Bindung geändert wird, wird daher die Marge in der Callback-Methode entsprechend angepasst. – bugged87

+0

@ bugged87 was ich mit der Datenbindung meinte, war die ursprüngliche Frage, nicht Ihre angefügte Eigenschaft Antwort. Natürlich funktioniert Databinding. Aber auf einer Struktur, die Thickness ist, können Sie Datenbindung nicht verwenden, außer es ist die Quelle. Kurz gesagt, ich habe nicht über MarginRight gesprochen, stattdessen habe ich über Margin.Right gesprochen. – dowhilefor

1

Obwohl eine angepasste Eigenschaft funktionieren kann. Ich würde versuchen, Ihren Code umzuformatieren, damit Sie keine Änderungen an der Benutzeroberfläche im Code vornehmen. Sie sollten so viel von der Benutzeroberfläche handhaben, wie Sie in der Entwurfsseite der Datei können. Ich versuche, das Codebehind von XAML-Dateien so wenig wie möglich zu verwenden, da es Probleme mit MVVM verursacht.

+1

Haben Sie Vorschläge zum Refactoring des Codes? Wenn dem XAML-Designer die erforderliche Funktionalität fehlt, scheint Code-Behind ein großartiger Ort zu sein, um zusätzliche Funktionen hinzuzufügen. Beachten Sie, dass eine angefügte Eigenschaft, die an einem einzelnen Ort definiert und verwaltet wird, nicht wirklich dasselbe ist, wie wenn Sie diesen Code in den Code-Behind jeder XAML-Datei schreiben. Ich denke, es hängt auch davon ab, was genau du im Code-Behind machst. Wenn Sie den Datenkontext ändern, verursachen Sie möglicherweise Probleme für das MVVM-Muster. Wenn Sie jedoch nur UI-Komponenten ändern, ist das wahrscheinlich in Ordnung. – bugged87

+0

Das hatte ich immer ein Problem mit ... der Code-Behind ist eine partielle Klasse mit dem XAML-Code ... es ist auf der gleichen Ebene wie der XAML. Wenn es nur für UI-bezogene Aktivitäten verwendet werden kann, ist es nicht anders als in XAML. – AshbyEngineer

1

Sie könnten den Rand an eine Eigenschaft (Zeichenfolge) in Ihrem MVVM binden. In Ihrem MVVM müssen Sie lediglich die einzelnen Eigenschaften (oben, rechts, unten, rechts) nachverfolgen.

können Sie Konverter verwenden, wie in: How to set a top margin only in XAML? oder Binding only part of the margin property of WPF control

+0

Die Datenbindung an eine Eigenschaft in meinem Ansichtsmodell würde dann bedeuten, dass mein Ansichtsmodell einen UI-Design-spezifischen Wert beibehalten müsste. Dies bricht das MVVM-Muster. – bugged87

+0

Ich stimme Ihnen vollkommen zu ... Wo zeichnen wir die Grenze zwischen "UI" -spezifischen Funktionen, wie das Färben von Zeilen nach Status. Wenn "Logik" beteiligt ist und der Code auf "anderen" Eigenschaften wie Serviceergebnissen und/oder Eigenschaften beruht, dann ist MVVM das ... Oder Sie können immer Verhaltensweisen anhängen. –