2012-02-04 12 views
5

Trong mô hình và kiểu xem của tôi, tôi có một phương thức có chữ ký là bool IsPropertyReadOnly(string propertyName). Phương thức này xác định nếu người dùng hiện đang đăng nhập có thể chỉnh sửa một giá trị thích hợp. Một vài người dùng sẽ có thể chỉnh sửa các giá trị thuộc tính và hầu hết những người dùng khác sẽ có quyền truy cập chỉ đọc.Làm cách nào để dữ liệu ràng buộc kết quả của phương pháp mô hình chế độ xem với thuộc tính TextBox?

Thay vì tạo thuộc tính để trả lại trạng thái chỉ đọc của từng thuộc tính của mô hình, tôi muốn kết buộc kết quả của IsPropertyReadOny đến thuộc tính TextBox.IsReadOnly.

Đây là cách tôi hình dung cú pháp:

<TextBox Text="{Binding Address, Mode=TwoWay}" 
     IsReadOnly="{Binding MethodName=IsPropertyReadOnly MethodParameter=Address}" 
/> 

Các DataContext chứa xem mô hình, vì vậy về cơ bản tôi cần phải ràng buộc IsReadOnly đến kết quả của cuộc gọi ((Class)this.DataContext).IsPropertyReadOnly("Address")

Có rất nhiều tài liệu trong sử dụng một số ObjectDataProvider, nhưng đối tượng cung cấp dữ liệu tạo ra một cá thể đối tượng mới không phải là thứ tôi muốn. Hơn nữa, để sử dụng một cá thể hiện có, tôi phải thực hiện nhiệm vụ trong mã-đằng sau. Một lần nữa, không phải những gì tôi muốn làm.

Từ nghiên cứu của tôi, có vẻ như một giải pháp kế thừa từ Binding hoặc MarkupExtension phù hợp hơn với nhu cầu của tôi.

Mọi trợ giúp sẽ được đánh giá cao.

+0

Đây có thể là một câu trả lời cho câu hỏi của bạn (câu trả lời cuối cùng có sử dụng chuyển đổi): [? Bind to một phương pháp trong WPF] (http://stackoverflow.com/questions/ 502250/bind-to-a-method-in-wpf) –

Trả lời

4

Tôi đề xuất sử dụng trình chuyển đổi. Đây là ví dụ.Giả sử bạn có một lớp ViewModel đơn giản:

class ViewModel 
{ 
    public string Read 
    { get; set; } 

    public string ReadWrite 
    { get; set; } 

    public bool IsPropertyReadOnly(string propertyName) 
    { 
     return propertyName != "ReadWrite"; 
    } 
} 

Để giải quyết vấn đề của bạn, bạn cần phải viết một bộ chuyển đổi, chẳng hạn như:

public class Converter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     var vm = value as ViewModel; 
     var functionName = (string)parameter; 

     var result = vm.IsPropertyReadOnly(functionName); 
     return result; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException("This method should never be called"); 
    } 
} 

Và đó là tất cả; bây giờ bạn có thể sử dụng chuyển đổi này trong XAML, như:

<Window.Resources> 
    <temp:Converter x:Key="ReadOnlyMethodConverter"/> 
</Window.Resources> 
<StackPanel> 
    <TextBox Text="{Binding Read, Mode=TwoWay}" 
      IsReadOnly="{Binding Path=., 
     Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=Read}" 
    /> 
    <TextBox Text="{Binding ReadWrite, Mode=TwoWay}" 
      IsReadOnly="{Binding Path=., 
     Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=ReadWrite}" 
    /> 
</StackPanel> 

Và trong code-behind chúng ta chỉ cần tạo ViewModel và thiết lập nó như DataContext:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel(); 
    } 
} 
+0

Mặc dù tôi đã sử dụng đề xuất của H.B. trong một câu trả lời khác, tôi chấp nhận và bỏ phiếu cho câu trả lời này bởi vì tôi nghĩ rằng nó hoàn toàn trả lời câu hỏi về ràng buộc với một phương pháp với các tham số trên mô hình khung nhìn. – AMissico

+3

Tôi nghĩ có quá nhiều câu trả lời trong phần bình luận trước. : O) – AMissico

0

Bạn có thể thực hiện việc này bằng cách sử dụng ObjectDataProvider để thực thi phương pháp và sau đó ràng buộc thuộc tính đính kèm với giá trị trả lại của nhà cung cấp.

Trước tiên, bạn sẽ cần phải cấu hình các nhà cung cấp như một nguồn lực:

<Window.Resources> 
    <ObjectDataProvider x:Key="readOnlyProvider" ...> 
    <ObjectDataProvider.MethodParameters> 
     ... 
    </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 
</Window.Resources> 

Sau đó sử dụng các nhà cung cấp như là nguồn gốc của tài sản gắn liền của bạn ràng buộc:

<TextBox Text="{Binding PoolNum, Mode=OneWay}" Windows:AttachedProperties.IsReadOnlyOn="{Binding Source={StaticResource readOnlyProvider}}" /> 

Phần khó khăn của quá trình này sẽ "chuyển" giá trị cho số ObjectDataProviders.MethodParameters. Điều này có thể được thực hiện trong XAML và có một số tài nguyên ngoài đó để chỉ cho bạn cách nó được thực hiện; đây là một để bắt đầu: http://weblogs.asp.net/psheriff/archive/2010/02/23/bind-objectdataprovider-method-parameters-in-wpf.aspx

CẬP NHẬT

mỗi nhận xét của bạn, đây là hai phương diện, ObjectDataProvider có thể thực hiện phương pháp này trên quan điểm của bạn của DataContext mà không cần tạo một đối tượng mới.

Trước tiên, hãy phương pháp xem mô hình của bạn tĩnh và sử dụng ObjectType tài sản:

<ObjectDataProvider x:Key="readOnlyProvider" 
    ObjectType="{x:local MyDataContext}" 
    MethodName="IsPropertyReadOnly"> 
    ... 
</ObjectDataProvider> 

Hoặc, thiết lập ObjectInstance của nhà cung cấp đến quan điểm của DataContext khi xem tải:

public class MyWindow : Window 
{ 
    public MyWindow() 
    { 
    InitializeComponent(); 

    var readOnlyProvider = this.Resources["readOnlyProvider"] as ObjectDataProvider; 
    readOnlyProvider.ObjectInstance = this.DataContext; 
    } 
} 

Có không có cách nào để liên kết với các phương thức trong XAML và cách giải quyết duy nhất mà tôi biết là sử dụng số ObjectDataProvider.

+0

Nhưng, tôi không muốn 'ObjectDataProvider' tạo một đối tượng mới. Sẽ tốt hơn nếu tôi có thể đặt đối tượng của nhà cung cấp. – AMissico

4

Hơn nữa, sử dụng một thể hiện tôi phải thực hiện nhiệm vụ trong mã sau. Một lần nữa, không phải những gì tôi muốn làm.

Điều đó không đúng, tuy nhiên lựa chọn của bạn sẽ bị giới hạn.


Làm thế nào để lập chỉ mục?

private readonly Dictionary<string, bool> _PropertyReadOnlyDictionary = new Dictionary<string, bool>(); 
public Dictionary<string, bool> PropertyReadOnlyDictionary { get { return _PropertyReadOnlyDictionary; } } 
<TextBox Text="{Binding Address, Mode=TwoWay}" 
     IsReadOnly="{Binding PropertyReadOnlyDictionary[Address]}" /> 

Bạn có thể dĩ nhiên quấn phương pháp của bạn trong một lớp học mới cho phép truy cập thông qua một indexer cũng như nếu bạn không muốn sử dụng một cuốn từ điển.

private readonly PropertyIsReadOnlyResolver _PropertyIsReadOnlyResolver = new PropertyIsReadOnlyResolver(); 
public PropertyIsReadOnlyResolver PropertyIsReadOnlyResolver { get { return _PropertyIsReadOnlyResolver; } } 
public class PropertyIsReadOnlyResolver 
{ 
    public bool this[string propertyName] 
    { 
     get 
     { 
      return IsPropertyReadOnly(propertyName); 
     } 
    } 

    public bool IsPropertyReadOnly(string propertyName) 
    { 
     //... 
    } 
} 
<TextBox Text="{Binding Address, Mode=TwoWay}" 
     IsReadOnly="{Binding PropertyIsReadOnlyResolver[Address]}" /> 
+0

Thú vị, chúng tôi đã sử dụng một người lập chỉ mục lúc đầu. Tôi quyết định chống lại nó bởi vì chúng ta cần sử dụng 'IDataErrorInfo'. Tôi thích người lập chỉ mục đầu tiên với từ điển vì nó phù hợp với việc triển khai của chúng tôi tốt hơn. – AMissico

+0

Chúng tôi đã sử dụng tính năng thực thi PropertyReadOnlyDictionary và nó được tích hợp hoàn hảo với thiết kế của chúng tôi. Cảm ơn nhiều. – AMissico

+0

@AMissico: Rất vui khi biết điều đó :) –