2012-09-28 7 views
8

Questo è abbastanza facile da fare da code-behind:Come si modifica SOLO il valore corretto (o sinistro, superiore, inferiore) della proprietà Margine di un controllo WPF?

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

in XAML, però, io sono limitati a quanto segue:

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

Il problema di questo è che ora ho potenzialmente sovrascritto gli altri valori di margine (cioè a sinistra, in alto, in basso) impostandoli a zero).

C'è un modo per avere XAML come il seguente?

<Button MarginRight="10" /> 

risposta

7

È possibile utilizzare una proprietà associata. In effetti, questo è esattamente lo scopo delle proprietà associate: accedere alle proprietà dell'elemento genitore o aggiungere funzionalità aggiuntive a un elemento specifico.

Ad esempio, definire la seguente classe da qualche parte nell'applicazione:

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

Ora nel tuo XAML tutto quello che devi fare è dichiarare il seguente spazio:

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

E poi si può scrivere XAML come il seguente:

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



In alternativa, è possibile evitare di utilizzare una proprietà allegata e invece scrivere un po 'un po' più lungo XAML come ad esempio:

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

+3

Che XAML alla fine è la stessa cosa di 'Margine = "0,0,10,0"' come si sovrascrive quello esistente 'Thickness' se ci è uno. –

+1

@ H.B. Grazie, avrei dovuto provare quell'ultima parte. Hai ragione. L'intero margine verrebbe riassegnato e tutti i valori non specificati verrebbero restituiti ai valori predefiniti. Ho modificato la risposta per contrassegnare quella parte. – bugged87

0

Tu sei sbagliato in questa parte:

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

erro R CS1612: non è possibile modificare il valore di ritorno di 'System.Windows.FrameworkElement.Margin' perché non è una variabile

è già non codice valido, perché restituisce un margine struct ed è quindi un tipo di valore. E poiché non deriva da DependencyObject, anche molti trucchi DataBinding non funzioneranno.

Volevo solo dare una spiegazione adeguata, altrimenti direi che la tua prima risposta è praticamente l'unico modo.

+0

@ dowhilefor Hai ragione sulla parte code-behind. Errore di battitura da parte mia. Ho aggiornato la mia domanda per riflettere ciò che intendevo in realtà. Tuttavia, DataBinding funzionerà perché la proprietà MarginRight è un DependencyObject. Pertanto, ogni volta che il valore della proprietà viene modificato tramite associazione, il Margine verrà adeguato di conseguenza nel metodo di callback. – bugged87

+0

@ bugged87 cosa intendevo per il databinding, era la domanda originale, non la tua risposta alla proprietà allegata. Certo che funziona con il databinding. Ma su una struttura, che è lo spessore, non è possibile utilizzare il databinding a meno che non sia la fonte, naturalmente. In breve, non stavo parlando di MarginRight, invece parlavo di Margin.Right. – dowhilefor

1

Anche se una proprietà attatched può funzionare. Vorrei provare a rifattorizzare il codice in modo da non apportare modifiche all'interfaccia utente nel codice sottostante. Dovresti gestire la maggior parte dell'interfaccia utente che puoi all'interno del design del file. Cerco di usare il codebehind dei file xaml il meno possibile perché causa problemi con MVVM.

+1

Avete suggerimenti per il refactoring del codice? Se il progettista XAML manca delle funzionalità richieste, sembra che code-behind sia un ottimo posto per aggiungere funzionalità extra. Tieni presente che una proprietà associata definita e gestita in un'unica posizione non corrisponde esattamente alla scrittura di quel codice nel code-behind di ciascun file XAML. Immagino che dipenda anche da cosa stai facendo esattamente nel code-behind. Se stai modificando il contesto dei dati, allora sì potresti causare problemi per il pattern MVVM. Tuttavia, se stai solo modificando i componenti dell'interfaccia utente, probabilmente è corretto. – bugged87

+0

Ho sempre avuto un problema con ... il code-behind è una classe parziale con il codice XAML ... è allo stesso livello di XAML. Se può essere usato per fare solo attività legate all'interfaccia utente, non è diverso da farlo in XAML. – AshbyEngineer

1

È possibile che i dati vincolino il Margine a una proprietà (stringa) nel MVVM. Nel tuo MVVM, tutto ciò che ti serve è tracciare le singole proprietà (in alto, a destra, in basso, a destra).

È possibile utilizzare convertitori come in: How to set a top margin only in XAML? o Binding only part of the margin property of WPF control

+0

L'associazione dei dati a una proprietà nel mio modello di vista significherebbe quindi che il mio modello di visualizzazione dovrebbe mantenere un valore specifico per la progettazione dell'interfaccia utente. Questo rompe il modello MVVM. – bugged87

+0

Sono assolutamente d'accordo con te ... Dove tracciamo la linea tra le funzionalità specifiche della "UI", come colorare le righe in base allo stato. Se è coinvolta la "logica" e il codice si basa su "altre" proprietà come i risultati del servizio e/o le proprietà, allora MVVM è ... Oppure, è sempre possibile allegare comportamenti. –

Problemi correlati