2012-06-11 32 views
6

Estoy intentando crear un proxy de propiedad de dependencia simple. Hice un control personalizado, es un selector de archivos, que está hecho de un cuadro de texto (nombre: "TextBox_FilePath") y un botón que muestra el cuadro de diálogo de abrir archivo.Crear un proxy para una propiedad de dependencia

Como estoy haciendo un control reutilizable me gustaría tener una propiedad "SelectedFilePath". Como la propiedad Text parece ser perfecta para que mi control sea la propiedad "SelectedFilePath", me gustaría realizar un proxy de estas propiedades de dependencia.

El primer enfoque que hice fue:

public static readonly DependencyProperty SelectedFilePathProperty = TextBox.TextProperty; 

public string SelectedFilePath 
{ 
    get { return (string) this.TextBox_FilePath.GetValue(SelectedFilePathProperty); } 
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); } 
} 

que funcionó, pero THROWED una excepción cuando se trata de obligar a esa propiedad. Luego salí con:

public static readonly DependencyProperty SelectedFilePathProperty = 
    DependencyProperty.Register("SelectedFilePath", typeof (string), typeof (FilePicker), new PropertyMetadata(default(string))); 

public string SelectedFilePath 
{ 
    get { return (string) this.TextBox_FilePath.GetValue(SelectedFilePathProperty); } 
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); } 
} 

que funciona, pero no tengo ni idea de por qué ?! ¿Dónde especifiqué que quería la propiedad text del cuadro de texto?

¿Qué me hace falta simplemente para representar por proxy esa propiedad de dependencia?

EDIT: La solución con AddOwner no funciona demasiado, se produce una Excetion diciendo "sólo puede ser aplicado en una propiedad de dependencia de unión". Código:

public static readonly DependencyProperty SelectedFilePathProperty = 
    TextBox.TextProperty.AddOwner(typeof(FilePicker)); 

public string SelectedFilePath 
{ 
    get { return (string)this.TextBox_FilePath.GetValue(SelectedFilePathProperty); } 
    set { this.TextBox_FilePath.SetValue(SelectedFilePathProperty, value); } 
} 

¿Qué no entiendo?

Edit2: para todos los demás que tienen problemas para entender la respuesta, he hecho a little graphic

Respuesta

3

El primer enfoque no funciona porque la propiedad es registrados sólo para el TextBox, añadiendo una referencia en otro la clase no hace nada

El segundo solo crea una propiedad de cadena completamente nueva.

Si realmente desea reutilizar la llamada TextBox.TextPropertyAddOwner en él.

p. Ej.

public static readonly DependencyProperty SelectedFilePathProperty = 
    TextBox.TextProperty.AddOwner(typeof(FilePicker)); 

(Tenga en cuenta que esta propiedad está registrada como "Text", por lo que es probable que sólo debe crear una nueva propiedad con el nombre que desea como ya lo hizo. También recomendaría a set metadata flags a bind two-way by default si usted quiere tener la mismo comportamiento vinculante que TextBox.Text.)

+0

favor ver mi edición :) – GameScripting

+0

* * Como ya he dicho, está registrado con el nombre de "texto", se puede, por tanto, sólo se unen a una propiedad llamada 'Text', la propiedad' SelectedFilePath' que creó es solo un contenedor para su código imperativo, las encuadernaciones nunca lo usan. Registre su propiedad si quiere un nombre diferente. –

+0

¿Puede ser tan amable y dar un ejemplo o dar alguna referencia sobre cómo hacer eso? – GameScripting

1

Esta solución es un poco complicada pero funciona.

Dado este control de usuario:

<Grid> 
    <StackPanel> 
     <WpfApplication1:FilePicker SelectedFilePath ="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <TextBlock Text="{Binding MyProperty}" /> 
    </StackPanel> 
</Grid> 

Y su modelo de vista:

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    #region Implementation of INotifyPropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void OnPropertyChanged(string e) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(e)); 
    } 

    #endregion 

    private string _myProperty; 
    public string MyProperty 
    { 
     get { return _myProperty; } 
     set 
     { 
      _myProperty = value; 
      OnPropertyChanged("MyProperty"); 
     } 
    } 
} 

XAML para el control FilePicker:

<Grid> 
    <TextBox x:Name="TextBox_FilePath" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type WpfApplication1:FilePicker}}}" Text="{Binding SelectedFilePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
</Grid> 

CodeBehind para el control FilePicker:

public partial class FilePicker : UserControl 
{ 
    public FilePicker() 
    { 
     InitializeComponent(); 
    } 

    /* private PROXY DP*/ 
    private static readonly DependencyProperty TextProperty = 
     TextBox.TextProperty.AddOwner(typeof(FilePicker)); 

    /* public DP that will fire getter/setter for private DP */ 
    public static readonly DependencyProperty SelectedFilePathProperty = 
     DependencyProperty.Register("SelectedFilePath", typeof(string), typeof(FilePicker), new PropertyMetadata(default(string))); 

    public string SelectedFilePath 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 
} 

Funciona como un encanto.

+0

Gist completo se puede encontrar aquí: https://gist.github.com/2917066 –

+0

Muchas gracias, sin su ejemplo ¡no lo haría funcionar! – GameScripting

0

Como tenía problemas para entender H.B.s answer hice un pequeño gráfico que me ayudó a entender lo que sucede debajo del capó. Aquí está;

enter image description here

Tal vez ayuda a otra persona :)

+0

Ahora entiendo qué es lo que no conseguiste: P –

Cuestiones relacionadas