Binding Silverlight UserControl custom properties

2019-03-14 20:03发布

I'm trying to make a simple crossword puzzle game in Silverlight 2.0. I'm working on a UserControl-ish component that represents a square in the puzzle. I'm having trouble with binding up my UserControl's properties with its' elements. I've finally (sort of) got it working (may be helpful to some - it took me a few long hours), but wanted to make it more 'elegant'.

I've imagined it should have a compartment for the content and a label (in the upper right corner) that optionally contains its' number. The content control probably be a TextBox, while label control could be a TextBlock. So I created a UserControl with this basic structure (the values are hardcoded at this stage):

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

I've also created DependencyProperties in the Square class like this:

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

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

Now I'd like to figure out how to bind the Label and Content element to the two properties. I do it like this (in the code-behind file):

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

That would be more elegant done in XAML. Does anyone know how that's done?

6条回答
Evening l夕情丶
2楼-- · 2019-03-14 20:15

Try this:

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

I can bind in both XAML and code behind.

查看更多
再贱就再见
3楼-- · 2019-03-14 20:16

I think you are looking for UI Element to Element Binding which is a feature of Silverlight 3.

查看更多
Deceive 欺骗
4楼-- · 2019-03-14 20:19

As Silverlight cannot use FindAncestor technique you can use a trick similar to the one that sets the UserControl's name, but without breaking its functionality by using the name of the 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>

It worked in SL3 without having to add any additional code (I'm using it in a WP7 app), but don't know if you can use it in SL2. Well, I realize now how this question is old, hope it's still helpful, I've arrived here because the answers I got for the same problem in WP7 didn't convince me.

查看更多
The star\"
5楼-- · 2019-03-14 20:21

I may not be understanding your issue exactly. In Silverlight, you are able to bind to almost any data object. So, if you have a PuzzleSquare class that contains properties Content and Label, you may bind to these properties directly from the object.

Let's say you created a simple object 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;
      }    
    }

So, if you are building the app with the classic view/code behind model, your code behind would add this object to the DataContext property of the grid on page load:

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

Your Xaml would bind to the Square property:

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

Does that make sense?

ib.

查看更多
成全新的幸福
6楼-- · 2019-03-14 20:30

First, set the DataContext on the UserControl using {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}}">

Now you can bind the individual elements to the properties of the 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" />

For SL 2.0, you'll need to set the DataContext on the UserControl's Loaded event handler.

private void UserControl_Loaded( object sender, RoutedEventArgs e ) {
    LayoutRoot.DataContext = this;
}
查看更多
Emotional °昔
7楼-- · 2019-03-14 20:37

This worked in Silverlight 4.0

Put a name on the UserControl, and then refer to it in the TextBlock

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

        <TextBlock x:Name="Label" ...
            Text="{Binding Path=LabelText,ElementName=Square}"/>
查看更多
登录 后发表回答