2012-04-20 10 views
6

Tengo mi propio UserControl, un LabeledTextBox que es la combinación de un Label y un ... bueno, TextBox. Este control tiene dos propiedades: Caption que se vinculará a la leyenda Label y Value que se vinculará al Text del TextBox.Cómo utilizar el enlace TwoWay desde un UserControl?

Código:

public class LabeledTextBox : Control 
{ 
    static LabeledTextBox() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledTextBox), new FrameworkPropertyMetadata(typeof(LabeledTextBox))); 
    } 

    public string Caption 
    { 
     get { return (string)GetValue(CaptionProperty); } 
     set { SetValue(CaptionProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Caption. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty CaptionProperty = 
     DependencyProperty.Register("Caption", typeof(string), typeof(LabeledTextBox), new UIPropertyMetadata("")); 


    public string Value 
    { 
     get { return (string)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", typeof(string), typeof(LabeledTextBox), new UIPropertyMetadata("")); 


} 

XAML:

<Style TargetType="{x:Type local:LabeledTextBox}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:LabeledTextBox}"> 
       <Grid> 
        <Grid> 

        <Grid.RowDefinitions> 
         <RowDefinition /> 
         <RowDefinition /> 
        </Grid.RowDefinitions> 

        <Label Grid.Row="0" Content="{TemplateBinding Caption}" /> 
        <TextBox Name="Box" Margin="3,0,3,3" Grid.Row="1" Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" /> 

        </Grid> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Uso:

<uc:LabeledTextBox Caption="Code:" Value="{Binding ExpenseCode}" /> 

Al principio pensé que había encontrado mi respuesta aquí: WPF TemplateBinding vs RelativeSource TemplatedParent

que detalla los diferen ce entre TemplateBinding y RelativeSource TemplatedParent. Cambié mi código en consecuencia, pero aún siento que me falta un paso. El enlace OneWay funciona, mi cuadro de texto está vinculado a la propiedad Value, pero los cambios no se registran.

¿Cómo hago para que funcione?

+0

¿Ha intentado hacer también su propiedad de dependencia de valor TwoWay? ¿O es el problema que el TextBox no escribe en su Value dp? – dowhilefor

+0

¿Está 'LabeledTextBox.Value' que no está cambiando o es' ExpenseCode' en el objeto de datos? Puede agregar un [PropertyChangedCallback] (http://msdn.microsoft.com/en-us/library/system.windows.propertychangedcallback.aspx) a la propiedad de dependencia 'Value' para ver si se llama. – Clemens

+0

@dowhilefor: ¿no es eso para lo que es el 'Modo = TwoWay' en el XAML? @Clemens: Inicialmente tuve esa devolución de llamada, y me llamaron. En esa devolución de llamada, establecí el valor del cuadro de texto. ¿Debo hacer explícitamente que los datos vuelvan desde el DP? @Ricibob: gracias, pero ese no parece ser el caso. – diggingforfire

Respuesta

6

Cambie el modo aquí.

<uc:LabeledTextBox Caption="Code:" Value="{Binding ExpenseCode,Mode=TwoWay}" /> 

funcionó en mi extremo

+0

Genial, ¡eso funcionó! – diggingforfire

+1

Probé todas las posibles combinaciones de modo al estilo n la declaración. @dowhile tiene razón, gracias por la explicación :) – Akanksha

+0

Todavía no soy un experto en WPF, pero ese es un buen enfoque :) – diggingforfire

4

por si alguien tiene este problema:

Otro enfoque (quizás más elegante) sería declarar la propiedad de dependencia del control de usuario de una manera para que por defecto, es de enlace bidireccional (por ejemplo, como el marco de trabajo de TextBox por defecto).

Esto se puede lograr de la siguiente manera (tomado de la respuesta de this Stackoverflow question):

public DependencyProperty SomeProperty = 
     DependencyProperty.Register("Some", typeof(bool), typeof(Window1), 
      new FrameworkPropertyMetadata(default(bool), 
       FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

La clave aquí es utilizar FrameworkPropertyMetadata.

Cuestiones relacionadas