2009-04-08 27 views
17

Tôi đang cố tạo trò chơi ô chữ đơn giản trong Silverlight 2.0. Tôi đang làm việc trên một thành phần UserControl-ish đại diện cho một hình vuông trong câu đố. Tôi đang gặp rắc rối với việc ràng buộc các thuộc tính của UserControl với các phần tử của nó. Cuối cùng tôi đã (loại) nhận được nó làm việc (có thể hữu ích cho một số - nó đã cho tôi một vài giờ dài), nhưng muốn làm cho nó thêm 'thanh lịch'.Gắn kết các thuộc tính tùy chỉnh của Silverlight UserControl với 'các thành phần

Tôi đã tưởng tượng nó phải có ngăn chứa nội dung và nhãn (ở góc trên bên phải) có tùy chọn chứa số 'của nó. Việc kiểm soát nội dung có thể là một TextBox, trong khi kiểm soát nhãn có thể là một TextBlock. Vì vậy, tôi đã tạo ra một usercontrol với cấu trúc cơ bản này (các giá trị được mã hóa ở giai đoạn này):

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

Tôi cũng đã tạo DependencyProperties trong lớp Quảng trường như thế này:

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

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

Bây giờ tôi muốn muốn tìm ra cách liên kết phần tử Nhãn và Nội dung với hai thuộc tính. Tôi làm như thế này (trong tập tin phía sau mã):

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

Điều đó sẽ được thực hiện thanh lịch hơn trong XAML. Có ai biết làm thế nào được thực hiện?

+3

Câu hỏi quan trọng như vậy chưa phải là một câu trả lời khó nắm bắt. –

Trả lời

1

Tôi có thể không hiểu chính xác vấn đề của bạn. Trong Silverlight, bạn có thể liên kết với hầu như bất kỳ đối tượng dữ liệu nào. Vì vậy, nếu bạn có một lớp PuzzleSquare chứa các thuộc tính Nội dung và Nhãn, bạn có thể liên kết trực tiếp với các thuộc tính này từ đối tượng.

Hãy nói rằng bạn đã tạo một PuzzleSquare đối tượng đơn giản:

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

Vì vậy, nếu bạn đang xây dựng ứng dụng với quan điểm cổ điển/code đằng sau mô hình, mã của bạn đằng sau sẽ thêm đối tượng này đến tài sản của DataContext lưới trên tải trang:

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

XAML của bạn sẽ liên kết với thuộc tính vuông:

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

Điều đó có hợp lý không?

ib.

+1

Điều đó có ý nghĩa, nhưng kịch bản của tôi thì khác. Trong trường hợp của bạn PuzzleSquare và giao diện người dùng là các lớp riêng biệt. Tôi chưa đến đó. Tôi vẫn đang định nghĩa lớp UI của mình. Tôi muốn thêm một thuộc tính công khai vào lớp UI của tôi, những gì liên kết với một thuộc tính phần tử con. Sau đó, tôi sẽ liên kết dữ liệu với giao diện người dùng công khai của giao diện người dùng. –

+0

Chạy ra khỏi ký tự ở đó .. Vì vậy, trong thiết kế của tôi, tôi sẽ sử dụng lớp của tôi như vậy .. Tuy nhiên, tôi cần phải kết nối thuộc tính Nội dung với một phần phụ của Square. Điều đó có ý nghĩa? –

2

Tôi nghĩ rằng bạn đang tìm kiếm UI Element to Element Binding đó là một tính năng của Silverlight 3.

+0

Như James Cadd đã nói: Điều này vi phạm nếu bạn tiêu thụ UserControl trong ứng dụng và đặt tên cho nó. –

19

Đầu tiên, đặt DataContext trên UserControl sử dụng {RelativeSource Tự}:

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

Bây giờ bạn có thể liên kết cá nhân các phần tử cho thuộc tính của 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" /> 

Đối với SL 2.0, bạn cần đặt DataContext trên bộ điều khiển sự kiện được tải của UserControl .

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

Đây không phải là cách ngược lại của các thực hành tốt MVVM? Trong thế giới MVVM, DataContext của UserControl sẽ được đặt thành ViewModel. Điều gì nếu tôi muốn ràng buộc một điều khiển để ViewModel, và một số khác đến một tài sản của UserControl của tôi? – JYL

+0

Tôi đồng ý với nhận xét ở trên - trừ khi tôi bỏ sót điều gì đó phá hủy tính hữu dụng của dữ liệu này bằng cách giả định rằng mọi thứ bạn liên kết trong thành phần sẽ nằm trong quyền kiểm soát. Ngoài thủ thuật ràng buộc với bố cục LayoutRoot, tôi không thấy bất kỳ cách hợp lý nào để làm điều này trong xaml và vì vậy tôi đang sử dụng để chỉ cho các phần tử một tên và khởi tạo chúng trong codebehind của tôi từ thuộc tính phụ thuộc. –

0

Làm việc này trong Silverlight 4.0

Đặt một tên trên UserControl, và sau đó đề cập đến nó trong TextBlock

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

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

Điều này sẽ bị hỏng nếu bạn sử dụng UserControl trong ứng dụng và đặt tên cho nó. –

+0

Nhưng vẫn còn loại giải pháp – Evgeny

7

Như Silverlight không thể sử dụng kỹ thuật FindAncestor bạn có thể sử dụng một thủ thuật tương tự như một trong đó đặt tên của UserControl, nhưng không có vi phạm chức năng của nó bằng cách sử dụng tên của 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> 

Nó hoạt động trong SL3 mà không cần thêm bất kỳ mã bổ sung nào (tôi đang sử dụng nó trong ứng dụng WP7), nhưng không biết bạn có thể sử dụng nó trong SL2. Vâng, tôi nhận ra bây giờ làm thế nào câu hỏi này là cũ, hy vọng nó vẫn còn hữu ích, tôi đã đến đây bởi vì những câu trả lời tôi nhận được cho cùng một vấn đề trong WP7 đã không thuyết phục tôi.

+0

Trong số các giải pháp trên trang này điều này có vẻ như chỉ có giá trị, tuy nhiên nó đủ khó xử mà tôi sẽ chỉ khởi tạo công cụ của tôi trong codebehind theo tên. –

0

Hãy thử điều này:

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 

tôi có thể ràng buộc ở cả hai XAML và mã phía sau.

Các vấn đề liên quan