2009-04-08 23 views
17

Estoy tratando de hacer un juego de crucigramas simple en Silverlight 2.0. Estoy trabajando en un componente UserControl-ish que representa un cuadrado en el rompecabezas. Tengo problemas para enlazar las propiedades de UserControl con sus 'elementos. Finalmente (de alguna manera) funcionó (puede ser útil para algunos, me tomó algunas horas largas), pero quería hacerlo más 'elegante'.Enlace Silverlight UserControl propiedades personalizadas a sus 'elementos

Imagino que debería tener un compartimento para el contenido y una etiqueta (en la esquina superior derecha) que opcionalmente contiene su número. El control de contenido probablemente sea un TextBox, mientras que el control de etiqueta podría ser un TextBlock. Así que creé un control de usuario con esta estructura básica (los valores están codificados en esta etapa):

<UserControl x:Class="XWord.Square" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    FontSize="30" 
    Width="100" Height="100"> 
     <Grid x:Name="LayoutRoot" Background="White"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="Auto"/> 
      </Grid.ColumnDefinitions> 

      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
       <RowDefinition Height="*"/> 
      </Grid.RowDefinitions> 

      <TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
       Text="7"/> 
      <TextBox x:Name="Content" Grid.Row="1" Grid.Column="0" 
       Text="A" 
       BorderThickness="0" /> 

     </Grid> 
    </UserControl> 

También he creado DependencyProperties en la clase de la plaza de esta manera:

 public static readonly DependencyProperty LabelTextProperty; 
    public static readonly DependencyProperty ContentCharacterProperty; 

    // ...(static constructor with property registration, .NET properties 
    // omitted for brevity)... 

Ahora me gustaría averiguar cómo vincular el elemento Etiqueta y Contenido a las dos propiedades. Lo hago así (en el archivo de código subyacente):

 Label.SetBinding(TextBlock.TextProperty, new Binding { Source = this, Path = new PropertyPath("LabelText"), Mode = BindingMode.OneWay }); 
    Content.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("ContentCharacter"), Mode = BindingMode.TwoWay }); 

Eso sería más elegante hecho en XAML. ¿Alguien sabe cómo se hace eso?

+3

Una pregunta tan importante pero una respuesta tan elusiva. –

Respuesta

1

Es posible que no entienda el problema exactamente. En Silverlight, puede vincular a casi cualquier objeto de datos. Por lo tanto, si tiene una clase PuzzleSquare que contiene propiedades Contenido y Etiqueta, puede enlazar a estas propiedades directamente desde el objeto.

Digamos que ha creado un simple PuzzleSquare objeto:

public class PuzzleSquare 
    { 
     public string Content{ get; set; } 
     public string Label{ get; set; } 

     public void PuzzleSquare(){}; 
     public void PuzzleSquare(string label, string content):this() 
     { 
     Content = content; 
     Label = label; 
     }  
    } 

lo tanto, si usted está construyendo la aplicación con la vista clásica/código detrás de modelo, el código detrás añadiría este objeto a la propiedad DataContext del rejilla en la página de carga:

LayoutRoot.DataContext = new PuzzleSquare("1", "A"); 

Su Xaml se uniría a la propiedad la plaza:

<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
Text="{Binding Label}"/>    
    <TextBox x:Name="Content" Grid.Row="1" Grid.Column="0" 
Text="{Binding Content}" BorderThickness="0" /> 

¿Eso tiene sentido?

ib.

+1

Eso tiene sentido, pero mi escenario es diferente. En tu caso, PuzzleSquare y la UI son clases separadas. No estoy tan lejos todavía. Todavía estoy definiendo mi clase de UI. Quiero agregar una propiedad pública a mi clase de IU lo que se une a una propiedad de subelemento. Luego vincularé los datos al soporte público de la interfaz de usuario. –

+0

Se agotó el número de caracteres allí .. Por lo tanto, en mi diseño, utilizaré mi clase como .. Sin embargo, necesito conectar la propiedad Content a un elemento secundario de Square. ¿Tiene sentido? –

2

creo que busca UI Element to Element Binding que es una característica de Silverlight 3.

+0

Como dijo James Cadd: Esto se rompe si consume el UserControl en la aplicación y le da un nombre. –

19

En primer lugar, establecer el DataContext en el control de usuario utilizando RelativeSource {Auto}:

<UserControl x:Class="XWord.Square" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
FontSize="30" 
Width="100" Height="100" 
DataContext="{Binding RelativeSource={RelativeSource Self}}"> 

ya se puede obligar a la persona elementos a las propiedades del control de usuario:

<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
Text="{Binding LabelText}"/> 
<TextBox x:Name="Content" Grid.Row="1" Grid.Column="0" 
Text="{Binding ContentCharacter}" BorderThickness="0" /> 

para SL 2.0, se tendrá que establecer el DataContext en el controlador de eventos Loaded del UserControl .

private void UserControl_Loaded(object sender, RoutedEventArgs e) { 
    LayoutRoot.DataContext = this; 
} 
+0

¿No es esta la manera opuesta a las buenas prácticas de MVVM? En el mundo MVVM, el DataContext del UserControl debe establecerse en un ViewModel. ¿Qué pasa si quiero vincular un control al ViewModel y otro a una propiedad de UserControl? – JYL

+0

Estoy de acuerdo con el comentario anterior: a menos que me falta algo, esto destruye la utilidad del contexto de datos al asumir que todo lo que enlaza en el componente estará en el control. Aparte del truco de vincular al padre de LayoutRoot, no veo ninguna manera razonable de hacerlo en xaml, por lo que estoy recurriendo simplemente a darles un nombre a los elementos e inicializarlos en mi código detrás de la propiedad de dependencia. –

0

Esto funcionó en Silverlight 4.0

poner un nombre en el control de usuario, y luego se refieren a ella en el TextBlock

<UserControl x:Class="XWord.Square" 
    ...omitted for brevity ... 
    x:Name="Square"> 

     <TextBlock x:Name="Label" ... 
      Text="{Binding Path=LabelText,ElementName=Square}"/> 
+1

Esto se rompe si consume el UserControl en la aplicación y le da un nombre. –

+0

Pero todavía tipo de solución – Evgeny

7

Como Silverlight no puede utilizar la técnica FindAncestor puede utilizar un truco similar a la que establece el nombre del control de usuario, pero sin rompiendo su funcionalidad utilizando el nombre de la LayoutRoot ...

<UserControl x:Class="XWord.Square" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
FontSize="30" 
Width="100" Height="100"> 
    <Grid x:Name="LayoutRoot" Background="White"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="Auto"/> 
     </Grid.ColumnDefinitions> 

     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 

     <TextBlock x:Name="{Binding Path=Parent.LabelText, ElementName=LayoutRoot}" Grid.Row="0" Grid.Column="1" 
      Text="7"/> 
     <TextBox x:Name="{Binding Path=Parent.ContentCharacter, ElementName=LayoutRoot}" Grid.Row="1" Grid.Column="0" 
      Text="A" 
      BorderThickness="0" /> 
    </Grid> 
</UserControl> 

se trabajó en SL3 sin tener que añadir ningún código adicional (lo estoy usando en una aplicación WP7), pero no sabe si puede usarlo en SL2. Bueno, ahora me doy cuenta de que esta pregunta es antigua, espero que siga siendo útil. He llegado aquí porque las respuestas que obtuve para el mismo problema en WP7 no me convencieron.

+0

De las soluciones en esta página, esta parece ser la única válida, sin embargo, es bastante incómodo que voy a simplemente inicializar mis cosas en el código subyacente por nombre. –

0

Prueba esto:

Public ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(ButtonEdit), New System.Windows.PropertyMetadata("", AddressOf TextPropertyChanged)) 
Public Property Text As String 
    Get 
     Return GetValue(TextProperty) 
    End Get 
    Set(ByVal value As String) 
     SetValue(TextProperty, value) 
    End Set 
End Property 
Private Sub TextPropertyChanged() 
    If String.IsNullOrEmpty(Text) Then 
     TextBox1.Text = "" 
    Else 
     TextBox1.Text = Text 
    End If 
End Sub 
Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles TextBox1.LostFocus 
    Text = TextBox1.Text 
End Sub 

puedo obligar tanto en XAML y código detrás.

Cuestiones relacionadas