Привязка пользовательских свойств Silverlight UserControl к его элементам - PullRequest
17 голосов
/ 08 апреля 2009

Я пытаюсь сделать простую игру-кроссворд в 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. Кто-нибудь знает, как это делается?

Ответы [ 6 ]

19 голосов
/ 26 апреля 2010

Сначала установите 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 в обработчике событий Loaded UserControl.

private void UserControl_Loaded( object sender, RoutedEventArgs e ) {
    LayoutRoot.DataContext = this;
}
7 голосов
/ 23 апреля 2011

Поскольку 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, не убедили меня.

2 голосов
/ 23 апреля 2009

Я думаю, что вы ищете Связывание элементов с элементом , которое является функцией Silverlight 3.

1 голос
/ 08 апреля 2009

Возможно, я не совсем понимаю вашу проблему. В 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" />

Имеет ли это смысл?

И.Б. *. * 1014

0 голосов
/ 28 сентября 2011

Попробуйте это:

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, так и код позади.

0 голосов
/ 09 июля 2010

Это работало в 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}"/>
...