[Silverlight]監聽指定控件(FrameworkElement)的依賴屬性(DependencyProperty)的更改
前言
轉載請注明出處:http://www.rzrgm.cn/ainijiutian
最近在silverlight項目使用Telerik的控件,遇到一個問題。就是使用RadBusyIndicator,當IsBusy = false時,其內的控件(以TextBox為例)的焦點會丟失。IsBusy綁定的是ViewModel的IsBusy屬性,Button點擊時調用ViewModel的異步耗時方法,耗時方法結束時設置IsBusy = false,再調用回調函數。在回調函數調用txtInput.Focus()。
1: <telerik:RadBusyIndicator x:Name="rbiBusy" IsBusy="{Binding IsBusy}">
2: <telerik:RadButton Content="Button" Name="button1" Click="button1_Click" />
3: <TextBox x:Name="txtInput" />
4: </telerik:RadBusyIndicator>
看樣子是沒什么問題的,但是實際情況是文本框不會獲取到焦點。經過跟蹤也發現txtInput.Focus()返回false。
正文
在谷歌狂搜,才發現RadBusyIndicator的IsBusy不靠譜,IsBusyIndicationVisible才是好孩子。反編譯也證明了這點,IsBusy設置為false時,在 AnimationManager.Play函數的回調里設置IsBusyIndicationVisible=false。不過IsBusyIndicationVisible定義的是private set,程序里不太好監控。官方論壇有一種解決方案,是定義一個有附加屬性的類,然后在文本框上增加local:Helper.EnsureFocus="{Binding IsBusyIndicationVisible, ElementName=rbiBusy}"。
1: public class Helper
2: {
3: private static void OnEnsureFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
4: {
5: if (!(bool)e.NewValue)
6: {
7: (d as Control).Focus();
8: }
9: }
10:
11: public static bool GetEnsureFocus(DependencyObject obj)
12: {
13: return (bool)obj.GetValue(EnsureFocusProperty);
14: }
15:
16: public static void SetEnsureFocus(DependencyObject obj, bool value)
17: {
18: obj.SetValue(EnsureFocusProperty, value);
19: }
20:
21: // Using a DependencyProperty as the backing store for EnsureFocus. This enables animation, styling, binding, etc...
22: public static readonly DependencyProperty EnsureFocusProperty =
23: DependencyProperty.RegisterAttached("EnsureFocus", typeof(bool), typeof(Helper), new PropertyMetadata(OnEnsureFocusChanged));
24: }
不過發現不能通用到其他場景。后來又發現一牛人2009年的帖子,才最終解決。
結語
整理如下。有興趣可以做成擴展方法。
1: public void ListenPropertyChanged(FrameworkElement element, string propertyName, PropertyChangedCallback callback)
2: {
3: Binding b = new Binding(propertyName) { Source = element }; //http://www.rzrgm.cn/ainijiutian
4: var prop = System.Windows.DependencyProperty.RegisterAttached("ListenAttached" + propertyName, typeof(object), typeof(FrameworkElement), new System.Windows.PropertyMetadata(callback));
5: element.SetBinding(prop, b);
6: }
使用
1: ListenPropertyChanged("IsBusyIndicationVisible", rbiBusy, (d, a) =>
2: {
3: if (!(bool)a.NewValue)
4: {
5: txtInput.Focus();
6: }
7: });

浙公網安備 33010602011771號