2009-05-10 30 views
14

Nói rằng tôi có một usercontrol rất đơn giản mà - cho tất cả các tính năng - là gì khác hơn là TextBox:Thiết Tuỳ chỉnh Properties trong UserControl qua DataBinding

public partial class FooBox : UserControl 
{ 
    public static readonly DependencyProperty FooTextProperty = 
     DependencyProperty.Register("FooText", typeof(string), typeof(FooBox)); 

    public FooBox() 
    { 
     InitializeComponent(); 
    } 

    public string FooText 
    { 
     get { return textBlock.Text; } 
     set { textBlock.Text = value; } 
    } 
} 

<UserControl x:Class="Namespace.FooBox" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="300" Width="300"> 
    <Grid> 
     <TextBlock x:Name="textBlock" /> 
    </Grid> 
</UserControl> 

Về hình thức nó khai báo là:

<local:FooBox FooText="{Binding Name}" /> 

DataContext của biểu mẫu được đặt thành đối tượng có thuộc tính Tên. Nhưng điều này không làm việc cho tôi. Tôi đang thiếu gì?

Trả lời

5

Biến vấn đề thực sự là tôi đã mong đợi khung công tác WPF đặt thuộc tính công khai của tôi, trong đó mã của tôi sẽ phản hồi các thay đổi và hiển thị theo giá trị mới. Không phải vậy. Những gì WPF làm là gọi SetValue() trực tiếp và hoàn toàn phá vỡ tài sản công cộng. Những gì tôi phải làm là nhận thông báo thay đổi thuộc tính bằng cách sử dụng DependencyPropertyDescriptor.AddValueChanged và trả lời điều đó. Nó trông giống như (bên trong ctor):

var dpd = DependencyPropertyDescriptor 
    .FromProperty(MyDependencyProperty, typeof(MyClass)); 
dpd.AddValueChanged(this, (sender, args) => 
{ 
    // Do my updating. 
}); 
+4

Cũng lưu ý rằng phương thức Đăng ký cho thuộc tính phụ thuộc có quá tải có thể chấp nhận trình xử lý sự kiện được kích hoạt bất cứ khi nào thuộc tính đang thay đổi hoặc đã thay đổi. Đó có thể là một nơi để đặt logic bạn có ở đó. –

19

Các phần "get" và "set" của khai báo thuộc tính trong DependencyProperty không thực sự được gọi bởi hệ thống databinding của WPF - chúng chủ yếu chỉ đáp ứng trình biên dịch.

Thay vào đó, thay đổi kê khai tài sản của bạn trông như thế này:

public string FooText 
{ 
    get { return (string)GetValue(FooTextProperty); } 
    set { SetValue(FooTextProperty, value); } 
} 

... và XAML của bạn để:

<UserControl ... 
    x:Name="me"> 
    <Grid> 
     <TextBlock Text="{Binding FooText,ElementName=me}" /> 
    </Grid> 
</UserControl> 

Bây giờ TextBox.Text của bạn chỉ đơn giản là liên kết trực tiếp đến "FooText" tài sản, do đó bạn có thể lần lượt liên kết thuộc tính FooText với "Tên" giống như bạn hiện đang làm.

Một cách khác là liên kết TextBlock.Text với liên kết RelativeSource tìm thuộc tính FooText trên tổ tiên đầu tiên của loại "FooBox", nhưng tôi thấy rằng điều này phức tạp hơn chỉ cho phép kiểm soát nội bộ x: Đặt tên và sử dụng phần tử ràng buộc.

+0

Tôi sẽ bỏ phiếu cho bạn vì bạn đã giúp tôi gần với những gì tôi đã bỏ lỡ. Nhưng trường hợp thử nghiệm của tôi ở đây quá đơn giản để phơi bày vấn đề thực sự. Xem câu trả lời của tôi. – xanadont