2010-09-22 39 views
8

Tôi có một ToggleButton với thuộc tính IsChecked của nó được liên kết với thuộc tính sử dụng liên kết OneWay.OneWay ràng buộc cho thuộc tính IsChecked ToggleButton trong WPF

<ToggleButton 
    Command="{Binding Path=SomeCommand}" 
    IsChecked="{Binding Path=SomeProperty, Mode=OneWay}" /> 

Các SomeCommand Toggles giá trị boolean SomeProperty, và một sự kiện PropertyChanged được nâng lên cho SomeProperty.

Nếu tôi thay đổi SomeProperty trong chế độ xem của mình, ToggleButton sẽ hiển thị chính xác. Tuy nhiên, nếu tôi nhấp vào ToggleButton, ràng buộc dường như bị mất và nút không còn được kiểm tra theo giá trị của SomeProperty. Bất kỳ ý tưởng về cách khắc phục sự cố này?

+0

SomeCommand của bạn làm gì? Tôi có một số ToggleButtons làm điều tương tự, với cùng một loại ràng buộc, và tất cả SomeCommand làm là phủ nhận giá trị hiện tại của SomeProperty. –

+0

SomeProperty thực sự là một loại khác và tôi đã sử dụng một công cụ chuyển đổi để thay đổi nó thành một boolean. Tôi bỏ điều đó ra để làm cho câu hỏi trở nên đơn giản hơn. –

Trả lời

4

Đây là thiết kế khi sử dụng gắn kết dữ liệu trên đường. Thêm thuộc tính đính kèm PresentationTraceSources.TraceLevel = Cao cho ràng buộc của bạn và bạn sẽ thấy khi nào nó bị ngắt kết nối. Liên kết này mô tả vấn đề này (không cung cấp bất kỳ giải pháp nào): Debugging Data Binding in WPF

Cách tôi thường giải quyết là sử dụng lệnh tương tác người dùng và mã phía sau để thay đổi giao diện điều khiển do một số thuộc tính đã thay đổi.

+0

Tại sao câu trả lời này được chấp nhận? Nó không giải quyết được vấn đề (tồn tại và có thể dễ dàng sao chép lại). – Sinatr

0

Tôi nghĩ vấn đề nảy sinh là xung đột giữa lệnh và liên kết IsChecked. Giải pháp của tôi là thay đổi viewmodel của tôi để lộ ra một số bool? và ràng buộc nó với thuộc tính IsChecked. Tôi không liên kết lệnh với số ToggleButton. Ở những nơi khác trong mã của tôi, nơi tôi muốn chuyển đổi tài sản tôi sử dụng SomeCommand.

10

Có một cách đơn giản và thanh lịch để giải quyết vấn đề các poster gốc - thay thế tài sản IsChecked của ToggleButton với một tài sản gắn thêm rằng sẽ thiết lập IsChecked của nút trong xử lý sự thay đổi của nó:

namespace TBFix 
{ 
    public class TBExtender 
    { 
    public static readonly DependencyProperty IsCheckedProperty = 
     DependencyProperty.RegisterAttached("IsChecked", 
              typeof(bool), 
              typeof(TBExtender), 
              new PropertyMetadata(OnChanged)); 

    public static bool GetIsChecked(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsCheckedProperty); 
    } 
    public static void SetIsChecked(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsCheckedProperty, value); 
    } 

    private static void OnChanged(DependencyObject o, 
            DependencyPropertyChangedEventArgs args) 
    { 
     ToggleButton tb = o as ToggleButton; 
     if (null != tb) 
     tb.IsChecked = (bool)args.NewValue; 
    } 
    } 
} 

XAML sau đó sẽ giống như thế này:

<ToggleButton Command="{Binding Path=SomeCommand}" 
       TBFix:TBExtender.IsChecked="{Binding Path=SomeProperty, 
                Mode=OneWay}" /> 

EDIT: giải pháp OP không hoạt động, vì khi nút được nhấn tài sản IsChecked được thiết lập trong các mã (đây là cách MS thực hiện kiểm soát ToggleButton) - thiết lập tài sản loại bỏ ràng buộc fr om nó và nó ngừng hoạt động.

Bằng cách sử dụng thuộc tính đính kèm, chúng tôi có thể khắc phục vấn đề này bởi vì nó không bao giờ được gán giá trị bằng mã và do đó các ràng buộc vẫn nguyên vẹn.

+0

Xin chào Alex, Cảm ơn bạn đã cung cấp giải pháp thanh lịch, nó hoạt động cho tôi. nhưng tôi không hiểu nó hoạt động ra sao. Bạn có thể giải thích thêm một chút không? –

+0

Tôi đã thêm vài từ vào ý tưởng đằng sau giải pháp của mình. Bạn có thể đọc thêm về các thuộc tính đính kèm trên MSDN (http://msdn.microsoft.com/en-us/library/vstudio/ms749011(v=vs.100).aspx) –

+0

Điều này thực sự là thanh lịch! – akshay2000

1

Tôi có vấn đề tương tự.

Đó là không"ràng buộc dường như bị mất" (trừ khi vấn đề khung trước đó của nó). Ràng buộc tiếp tục hoạt động và có thể dễ dàng được chứng minh bằng cách thay đổi thuộc tính bên ngoài lệnh đó (ví dụ: trong trình xử lý của một sự kiện/nút nhấp chuột khác).

Vấn đề là những gì IsChecked có thể được thay đổi bằng hai cách: 1) ràng buộc (khi giá trị của SomeProperty là nút thay đổi sẽ được cập nhật 2) sử dụng (nếu nút sử dụng báo chí, ông sẽ thay đổi IsChecked, nhưng ràng buộc là OneWay nên SomeProperty sẽ không được cập nhật).

Vì vậy, bạn có thể có desync xảy ra khi SomeProperty == false nhưng nút IsChecked == true hoặc ngược lại.

Để tối ưu hóa cơ chế ràng buộc hiệu suất, hãy kiểm tra xem giá trị mới có khác với hiện tại hay không. Vì vậy, nếu desync xảy ra và bạn cố gắng cập nhật SomeProperty với giá trị mà nó đã có, thì không có gì sẽ xảy ra.

Cách giải quyết rất đơn giản: cập nhật tài sản trong 2 bước

SomeProperty = !set; 
SomeProperty = set; 

nơi set là giá trị mà bạn cần (ví dụ đối diện với hiện tại SomeProperty).

0

Để hiểu biết của tôi Sinatr là chính xác về 'desync' xảy ra, ít nhất là trong các khuôn khổ mới hơn.

Một cách đơn giản khác xung quanh vấn đề là xóa chế độ = oneway và triển khai bộ đặt rỗng. Ví dụ:

bool _MyIsEnabled; 
    public bool MyIsEnabled 
    { 
     get { return _MyIsEnabled; } 
     set { } 
    } 

Với thiết lập ràng buộc này, bạn có thể thay đổi giá trị biến số sao lưu từ chức năng ràng buộc lệnh hoặc từ việc bạn cần. Chỉ cần nhớ gọi RaisePropertyChanged.

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