2012-09-28 14 views
8

Esto es bastante fácil de hacer a partir de código subyacente:¿Cómo modifico SOLAMENTE el valor correcto (o izquierdo, superior, inferior) de la propiedad Margen de un control WPF?

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

En XAML, sin embargo, yo estoy limitado a lo siguiente:

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

El problema con esto es que ahora tengo potencialmente sobrescribe los otros valores de margen (es decir, izquierda, arriba, abajo) al establecerlos en cero).

¿Hay alguna forma de tener XAML como el siguiente?

<Button MarginRight="10" /> 

Respuesta

7

Se puede utilizar una propiedad adjunta. De hecho, este es exactamente el propósito de las propiedades adjuntas: acceder a las propiedades del elemento principal o agregar funcionalidad adicional a un elemento específico.

Por ejemplo, defina lo siguiente clase en algún lugar de su aplicación:

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

En su XAML todo lo que hay que hacer es declarar el espacio de nombres siguiente:

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

Y entonces usted puede escribir XAML tales como los siguientes:

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



Como alternativa, se puede evitar el uso de una propiedad adjunta y en lugar de escribir algo un poco más larga XAML tales como:

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

+3

Eso XAML al final es lo mismo que 'Margen = "0,0,10,0"' como se sobrescribe el vigente 'Thickness' si hay es uno. –

+1

@ H.B. Gracias, debería haber probado esa última parte. Tienes razón. El margen completo se reasignaría y los valores no especificados se devolverían a los valores predeterminados. He editado la respuesta para marcar esa parte. – bugged87

0

Usted está equivocado con esta parte:

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

erro r CS1612: No se puede modificar el valor de retorno de 'System.Windows.FrameworkElement.Margin' porque no es una variable

está ya no código válido, porque devuelve un margen struct y por lo tanto es un tipo de valor. Y dado que no se deriva de DependencyObject, muchos trucos de DataBinding tampoco funcionarán.

Solo quería dar una explicación adecuada, de lo contrario diría que su primera respuesta es prácticamente la única.

+0

@ dowhilefor Tiene razón acerca de la parte del código subyacente. Typo de mi parte. He actualizado mi pregunta para reflejar lo que realmente quise decir. Sin embargo, DataBinding funcionará porque la propiedad MarginRight ES un DependencyObject. Por lo tanto, siempre que el valor de la propiedad se modifique a través de un enlace, el margen se ajustará en consecuencia en el método de devolución de llamada. – bugged87

+0

@ bugged87 Lo que quise decir con el enlace de datos, fue la pregunta original, no la respuesta de la propiedad adjunta. Por supuesto que funciona databinding. Pero en una estructura, que es Thickness, no se puede usar databinding a menos que sea la Fuente, por supuesto. En resumen, no estaba hablando de MarginRight, sino que estaba hablando de Margin.Right. – dowhilefor

1

Aunque una propiedad adjunta puede funcionar. Intentaría refactorizar su código para que no realice cambios en la interfaz de usuario en el código subyacente. Debe manejar la mayor parte de la interfaz de usuario que pueda dentro del lado del diseño del archivo. Intento usar el código detrás de los archivos xaml lo menos posible porque causa problemas con MVVM.

+1

¿Tiene alguna sugerencia para refactorizar el código? Si el diseñador XAML no tiene la funcionalidad requerida, parece que el código subyacente es un excelente lugar para agregar características adicionales. Tenga en cuenta que una propiedad adjunta definida y mantenida en un solo lugar no es realmente lo mismo que escribir ese código en el código subyacente de cada archivo XAML. Supongo que también depende exactamente de lo que estés haciendo en el código subyacente. Si está modificando el contexto de datos, entonces sí puede estar causando problemas para el patrón MVVM. Sin embargo, si solo está modificando los componentes de la interfaz de usuario, probablemente esté bien. – bugged87

+0

Esto siempre he tenido un problema con ... el código subyacente es una clase parcial con el código XAML ... está en el mismo nivel que el XAML. Si se puede usar para hacer solo actividades relacionadas con UI, no es diferente hacerlo en XAML. – AshbyEngineer

1

Puede enlazar los datos del Margen a una propiedad (cadena) en su MVVM. En tu MVVM, todo lo que necesitas es rastrear las propiedades individuales (arriba, derecha, abajo, derecha).

Puede utilizar convertidores como en: How to set a top margin only in XAML? o Binding only part of the margin property of WPF control

+0

El enlace de datos a una propiedad en mi modelo de vista significaría que mi modelo de vista tendría que mantener un valor que sea específico para el diseño de la UI. Esto rompe el patrón MVVM. – bugged87

+0

Estoy totalmente de acuerdo contigo ... ¿Dónde marcamos la línea entre la funcionalidad específica de "UI", como colorear filas según el estado. Si hay una "lógica" involucrada y el código se basa en "otras" propiedades como resultados de servicio y/o propiedades, entonces MVVM es ... O bien, siempre puede adjuntar comportamientos. –

Cuestiones relacionadas