[英]Attached Property. How to use SetValue in PropertyChangedCallback
我需要附加屬性,將焦點設置為ViewModel中的UIElement。 我已經創建了Attached屬性,在PropertyChangedCallback中我將焦點設置為UIElement。
private static void VoySetFocusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is UIElement)
{
if ((bool)e.NewValue)
{
(o as UIElement).Focus();
(o as UIElement).SetValue(VoySetFocusProperty, false);
}
}
}
但是我希望它像霰彈槍中的觸發器一樣工作。 我在ViewModel中設置為true ...它在MyAttachedProperties類中調用PropertyChangedCallback,將焦點設置為UIElement
((o as UIElement).Focus();
並且ViewModel中的Test值返回false
((o as UIElement).SetValue(VoySetFocusProperty, false);)
一切似乎都運行正常,但SetValue不會改變我在ViewModel中的值。
完整代碼:
視圖:
<Window x:Class="WpfAttachedProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAttachedProperty"
Title="MainWindow" Height="127" Width="316">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBox local:MyAttachedProperties.VoySetFocus="{Binding Path=Test,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Text="Focus Me"/>
<Button Grid.Row="1" Content="Click to Focus" HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" Width="75" Command="{Binding MyCommand}" />
</Grid>
代碼背后:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfAttachedProperty
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow:Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
/// <summary>
/// Command Class
/// </summary>
public class DelegateCommand:ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add
{
}
remove
{
}
}
}
/// <summary>
/// ViewModelClass
/// </summary>
public class ViewModel:INotifyPropertyChanged
{
private bool _test = false;
public bool Test
{
get
{
return _test;
}
set
{
_test = value;
this.NotifyPropertyChanged("Test");
}
}
public ICommand MyCommand
{
get
{
return new DelegateCommand(SetTestToTrue);
}
}
private void SetTestToTrue()
{
this.Test = true;
}
#region INotifyPropertyChanged
public void NotifyPropertyChanged(String PropertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
public class MyAttachedProperties
{
public static Object GetVoySetFocus(DependencyObject obj)
{
return (Object)obj.GetValue(VoySetFocusProperty);
}
public static void SetVoySetFocus(DependencyObject obj, Object value)
{
obj.SetValue(VoySetFocusProperty, value);
}
public static readonly DependencyProperty VoySetFocusProperty =
DependencyProperty.RegisterAttached("VoySetFocus", typeof(bool), typeof(MyAttachedProperties), new UIPropertyMetadata(false, new PropertyChangedCallback(VoySetFocusChanged), new CoerceValueCallback(CoerceVoySetFocus)));
private static object CoerceVoySetFocus(DependencyObject d, object baseValue)
{
return (bool)baseValue;
}
private static void VoySetFocusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is UIElement)
{
if ((bool)e.NewValue)
{
(o as UIElement).Focus();
// Doesn't set Test to false in ViewModel
(o as UIElement).SetValue(VoySetFocusProperty, false);
}
}
}
}
}
問候馬可。
問題在於:
((o as UIElement).SetValue(VoySetFocusProperty, false);)
您應該使用SetCurrentValue來設置DP。
((o as UIElement).SetCurrentValue(VoySetFocusProperty, false);)
說明 :
直接設置任何DependencyProperty的值會破壞它與source屬性的綁定。
但是, SetCurrentValue
不會破壞綁定並將值推回到source屬性。 MSDN對SetCurrentValue的解釋:
此方法由組件使用,該組件以編程方式設置其自身屬性之一的值,而不禁用應用程序聲明的屬性使用。 SetCurrentValue方法更改屬性的有效值,但現有的觸發器,數據綁定和樣式將繼續工作 。
此外,我認為在PropertyChanged
回調中設置它不會將其傳播回Viewmodel,如果它同步執行操作,因為它僅從Viewmodel屬性setter進行回調。
因此,我們可以做的是通過使用BeginInvoke
將它排入調度程序來異步執行此操作 ,以便它傳播到viewmodel Test屬性。
(o as UIElement).Focus();
Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate
{
// Doesn't set Test to false in ViewModel
(o as UIElement).SetCurrentValue(VoySetFocusProperty, false);
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.