Подтвердить что ты не робот

Связывание свойств Silverlight UserControl с его элементами

Я пытаюсь создать простую кроссвордную игру в Silverlight 2.0. Я работаю над компонентом UserControl-ish, который представляет собой квадрат в головоломке. У меня возникают проблемы с привязкой моих свойств UserControl со своими "элементами". Я наконец-то (вроде) получил его работу (может быть полезно для некоторых - мне потребовалось несколько долгих часов), но хотелось сделать его более "элегантным".

Я предположил, что у него должен быть отсек для контента и ярлык (в правом верхнем углу), который необязательно содержит его номер. Управление содержимым, вероятно, является TextBox, а управление меткой может быть TextBlock. Поэтому я создал UserControl с этой базовой структурой (значения на этом этапе жестко запрограммированы):

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

Я также создал DependencyProperties в классе Square следующим образом:

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

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

Теперь я хотел бы выяснить, как привязать элемент Label и Content к двум свойствам. Я делаю это так (в файле с кодом):

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

Это было бы более элегантно сделано в XAML. Кто-нибудь знает, как это сделано?

4b9b3361

Ответ 1

Сначала установите DataContext в UserControl с помощью {RelativeSource Self}:

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

Теперь вы можете привязать отдельные элементы к свойствам usercontrol:

<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" />

Для SL 2.0 вам необходимо установить DataContext в обработчике событий UserControl Loaded.

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

Ответ 2

Поскольку Silverlight не может использовать технику FindAncestor, вы можете использовать трюк, подобный тому, который устанавливает имя UserControl, но не нарушая его функциональность, используя имя 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>

Он работал в SL3 без необходимости добавлять дополнительный код (я использую его в приложении WP7), но не знаю, можете ли вы его использовать в SL2. Ну, теперь я понимаю, как этот вопрос старый, надеюсь, что он по-прежнему полезен, я приехал сюда, потому что ответы, которые я получил по той же проблеме в WP7, не убедили меня.

Ответ 4

Возможно, я не понимаю вашу проблему. В Silverlight вы можете привязываться практически к любому объекту данных. Итак, если у вас есть класс PuzzleSquare, который содержит свойства Content и Label, вы можете привязываться к этим свойствам непосредственно из объекта.

Скажем, вы создали простой объект PuzzleSquare:

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

Итак, если вы создаете приложение с классическим представлением/кодом за моделью, ваш код позади добавит этот объект к свойству DataContext сетки при загрузке страницы:

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

Ваш Xaml будет привязан к свойству Square:

    <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" />

Это имеет смысл?

И.Б..

Ответ 5

Это работало в Silverlight 4.0

Поместите имя в UserControl, а затем обратитесь к нему в TextBlock

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

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

Ответ 6

Попробуйте следующее:

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

Я могу связать как в XAML, так и в коде.