2009-10-06 12 views
16

¿Cuál es la forma correcta de implementar Custom Properties en Silverlight UserControls?Silverlight UserControl Custom Property Binding

Cada "Página" en Silverlight es técnicamente un UserControl (se derivan de la clase UserControl). Cuando digo UserControl aquí, me refiero a un UserControl personalizado que se utilizará en muchas páginas diferentes en muchos escenarios diferentes (similar a un control de usuario de ASP.NET).

Me gustaría que el Custom UserControl admita Binding y no confíe en el Nombre de la Propiedad a la que se vincula, siempre será el mismo. En su lugar, me gustaría que el UserControl tenga una propiedad a la que se unen los controles dentro del UserControl, y los ViewModels fuera de UserControl también se enlazan. (Consulte el ejemplo a continuación)

Enlazando dentro de las tareas de UserControl, Enlazando dentro de las obras de MainPage, La vinculación que configuré entre MainPage y UserControl no funciona. Específicamente esta línea:

<myUserControls:MyCustomUserControl x:Name="MyCustomControl2" 
    SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}" 
    Width="200" Height="50" /> 

ejemplo de salida:
alt text

MainPage.xaml

<UserControl x:Class="SilverlightCustomUserControl.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:myUserControls="clr-namespace:SilverlightCustomUserControl" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Canvas x:Name="LayoutRoot"> 
    <StackPanel Orientation="Vertical"> 
     <TextBlock Text="UserControl Binding:" Width="200"></TextBlock> 
     <myUserControls:MyCustomUserControl x:Name="MyCustomControl2" SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200" Height="50" /> 
     <TextBlock Text="MainPage Binding:" Width="200"></TextBlock> 
     <TextBox Text="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200"></TextBox> 
     <Border BorderBrush="Black" BorderThickness="1"> 
     <TextBlock Text="{Binding MainPageSelectedText}" Width="200" Height="24"></TextBlock> 
     </Border> 
    </StackPanel> 
    </Canvas> 
</UserControl> 

MainPage.xaml.cs

namespace SilverlightCustomUserControl 
{ 
public partial class MainPage : UserControl, INotifyPropertyChanged 
{ 
    //NOTE: would probably be in a ViewModel 
    public string MainPageSelectedText 
    { 
    get { return _MainPageSelectedText; } 
    set 
    { 
    string myValue = value ?? String.Empty; 
    if (_MainPageSelectedText != myValue) 
    { 
    _MainPageSelectedText = value; 
    OnPropertyChanged("MainPageSelectedText"); 
    } 
    } 
    } 
    private string _MainPageSelectedText; 


    public MainPage() 
    { 
    InitializeComponent(); 
    } 


    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged(string name) 
    { 
    PropertyChangedEventHandler ph = this.PropertyChanged; 

    if (ph != null) 
    ph(this, new PropertyChangedEventArgs(name)); 
    } 

    #endregion 
} 
} 

MyCustomUserControl.xaml

<UserControl 
    x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Grid> 
    <StackPanel> 
     <TextBox Text="{Binding SelectedText, Mode=TwoWay}" /> 
     <Border BorderBrush="Black" BorderThickness="1"> 
     <TextBlock Text="{Binding SelectedText}" Height="24"></TextBlock> 
     </Border> 
    </StackPanel> 
    </Grid> 
</UserControl> 

MyCustomUserControl.xaml.cs

namespace SilverlightCustomUserControl 
{ 
public partial class MyCustomUserControl : UserControl 
{ 
    public string SelectedText 
    { 
    get { return (string)GetValue(SelectedTextProperty); } 
    set { SetValue(SelectedTextProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedTextProperty = 
    DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback)); 


    public MyCustomUserControl() 
    { 
    InitializeComponent(); 
    } 

    private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
    //empty 
    } 
} 
} 

Referencias (cómo llegué hasta aquí):

uso DependencyPropertys: http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx

DependencyPropertys uso, añadir x: Nombre a su UserControl - agregar enlace con ElementName, establecer propiedad personalizada nuevamente en el método PropertyChangedCallback:

no utilizan las propiedades personalizadas, se basan en nombres DataContext subyacentes (no me gusta esta solución): wpf trouble using dependency properties in a UserControl

+0

Si están todavía en busca de respuesta que pueda consulte este artículo [Enlace de propiedad personalizado de Silverlight UserControl] (http://www.dotnetspark.com/kb/4664-silverlight-usercontrol-custom-property.aspx) –

Respuesta

7

lo entiendo como la razón de su control no está recibiendo el nuevo valor de la página de aguas calientes es que está configurando el DataContext del control. Si no lo ha hecho, el DataContext del control se heredará de su principal, la página principal en este caso.

Para que esto funcione, eliminé la configuración de DataContext de tu control, agregué una x: Name a cada control y establecí el enlace en el constructor del control usando el método [name] .SetBinding.

Realicé la vinculación en el controlador ya que no pude encontrar una forma de establecer la propiedad Origen del enlace declarativo en el xaml en Self. es decir, {Encuadernación de texto seleccionado, modo = doble, fuente = [Uno mismo aquí de alguna forma]}. Intenté usar RelativeSource = {RelativeSource Self} sin alegría.

NOTA: Todo esto es SL3.

+0

¡Sí! ¡Estos han sido mis pasos exactos desde esta publicación también! Voy a publicar un código un poco. Gracias por la ayuda. PD. RelativeSource = El uno mismo no funciona porque el DataContext se convierte en el TextBox, no el UserControl. –

+0

Por supuesto. Eso tiene total sentido. Gracias por hacérmelo saber. – voiddog

4

El problema era el control de usuario estaba lanzando un error de DataBinding (visible en la ventana de resultados durante la depuración)

Debido DataContext del UserControl se establece en "Auto" en su propio XAML, que estaba buscando el MainPageSelectedText dentro de su propio contexto (no buscaba el MainPageSelectedText dentro de "MainPage", que es donde podría pensar que se vería, porque cuando está físicamente escribiendo/mirando el código que está en "context")

I fue capaz de hacer que esto "funcionara" configurando el enlace en el código. Configurar el enlace en el código subyacente es la única forma de configurar UserControl como el "Origen" del enlace. Pero esto solo funciona si el enlace es bidireccional. El enlace OneWay romperá este código. Una mejor solución en conjunto sería crear un control de Silverlight, no un UserControl.

Ver también:

http://social.msdn.microsoft.com/Forums/en-US/silverlightcontrols/thread/052a2b67-20fc-4f6a-84db-07c85ceb3303

http://msdn.microsoft.com/en-us/library/cc278064%28VS.95%29.aspx

MyCustomUserControl.xaml

<UserControl 
    x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"> 
<Grid> 
    <StackPanel> 
    <TextBox x:Name="UserControlTextBox" /> 
    <Border BorderBrush="Black" BorderThickness="1"> 
    <TextBlock x:Name="UserControlTextBlock" Height="24"></TextBlock> 
    </Border> 
    </StackPanel> 
</Grid> 
</UserControl> 

MyCustomUserControl.xaml.cs

namespace SilverlightCustomUserControl 
{ 
public partial class MyCustomUserControl : UserControl 
{ 

    public string SelectedText 
    { 
    get { return (string)GetValue(SelectedTextProperty); } 
    set { SetValue(SelectedTextProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedTextProperty = 
    DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback)); 


    public MyCustomUserControl() 
    { 
    InitializeComponent(); 

       //SEE HERE 
    UserControlTextBox.SetBinding(TextBox.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText"), Mode = BindingMode.TwoWay }); 
    UserControlTextBlock.SetBinding(TextBlock.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText") }); 
       //SEE HERE 
    } 

    private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
    //empty 
    } 

} 
} 
0

En lugar de unirse contexto de datos a uno mismo, puede establecer la unión en XAML mediante la adición de un x:Name para el control de usuario y luego la unión en el xaml control de usuario sigue:

<UserControl 
    x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
    x:Name="myUserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"> 
    <Grid> 
     <StackPanel> 
      <TextBox Text="{Binding SelectedText, ElementName=myUserContol, Mode=TwoWay}" /> 
      <Border BorderBrush="Black" BorderThickness="1"> 
       <TextBlock Text="{Binding SelectedText,ElementName=myUserControl}" Height="24"></TextBlock> 
      </Border> 
     </StackPanel> 
    </Grid> 
</UserControl>