Распространение силы по принуждению
tl; dr: Принудительные значения не распространяются по привязкам данных. Как я могу форсировать обновление через привязку данных, когда код позадине знаю другую сторону переплета?
м, используяCoerceValueCallback
на свойство зависимости WPF и яЯ застрял в вопросе о том, что принуждать ценности неТ распространяется через привязки.
Window1.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace CoerceValueTest
{
public class SomeControl : UserControl
{
public SomeControl()
{
StackPanel sp = new StackPanel();
Button bUp = new Button();
bUp.Content = "+";
bUp.Click += delegate(object sender, RoutedEventArgs e) {
Value += 2;
};
Button bDown = new Button();
bDown.Content = "-";
bDown.Click += delegate(object sender, RoutedEventArgs e) {
Value -= 2;
};
TextBlock tbValue = new TextBlock();
tbValue.SetBinding(TextBlock.TextProperty,
new Binding("Value") {
Source = this
});
sp.Children.Add(bUp);
sp.Children.Add(tbValue);
sp.Children.Add(bDown);
this.Content = sp;
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(int),
typeof(SomeControl),
new PropertyMetadata(0, ProcessValueChanged, CoerceValue));
private static object CoerceValue(DependencyObject d, object baseValue)
{
if ((int)baseValue % 2 == 0) {
return baseValue;
} else {
return DependencyProperty.UnsetValue;
}
}
private static void ProcessValueChanged(object source, DependencyPropertyChangedEventArgs e)
{
((SomeControl)source).ProcessValueChanged(e);
}
private void ProcessValueChanged(DependencyPropertyChangedEventArgs e)
{
OnValueChanged(EventArgs.Empty);
}
protected virtual void OnValueChanged(EventArgs e)
{
if (e == null) {
throw new ArgumentNullException("e");
}
if (ValueChanged != null) {
ValueChanged(this, e);
}
}
public event EventHandler ValueChanged;
public int Value {
get {
return (int)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
}
public class SomeBiggerControl : UserControl
{
public SomeBiggerControl()
{
Border parent = new Border();
parent.BorderThickness = new Thickness(2);
parent.Margin = new Thickness(2);
parent.Padding = new Thickness(3);
parent.BorderBrush = Brushes.DarkRed;
SomeControl ctl = new SomeControl();
ctl.SetBinding(SomeControl.ValueProperty,
new Binding("Value") {
Source = this,
Mode = BindingMode.TwoWay
});
parent.Child = ctl;
this.Content = parent;
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(int),
typeof(SomeBiggerControl),
new PropertyMetadata(0));
public int Value {
get {
return (int)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
Window1.xaml
то есть два пользовательских элемента управления, один вложенный в другой, а внешний - в окне. Внутренний пользовательский элемент управления имеетValue
свойство зависимости, которое связано сValue
свойство зависимости внешнего управления. В окнеTextBox.Text
собственность связана сValue
свойство внешнего контроля.
Внутренний контроль имеетCoerceValueCallback
зарегистрирован с егоValue
свойство, эффект которого заключается в том, что этоValue
Свойству могут быть назначены только четные числа.
Обратите внимание, что этот код упрощен для демонстрационных целей. Реальная версия неинициализировать что-либо в конструкторе; два элемента управления на самом деле имеют шаблоны элементов управления, которые делают все, чтосделано в соответствующих конструкторах здесь. То есть в реальном коде внешний контроль нене знаю внутреннего контроля.
При записи четного числа в текстовое поле и изменении фокуса (например, путем фокусировки фиктивной кнопки под текстовым полем), обаValue
свойства должным образом обновляются. При записи нечетного числа в текстовое поле, однако,Value
свойство внутреннего контроля нет, в то время какValue
свойство внешнего контроля, а такжеTextBox.Text
свойство, показать нечетное число.
Мой вопрос:Как я могу принудительно обновить в текстовом поле (и в идеале также во внешнем элементе управленияValue
собственность, пока мына это)?
я нашелТАК вопрос по той же проблеме, но не делаетЯ действительно не могу найти решение. Это намекает на использование обработчика события, измененного свойством, для сброса значения, но, насколько я вижу, это означало бы дублирование кода оценки на внешний элемент управления ... что на самом деле не жизнеспособно, поскольку мой действительный код оценки полагается на некоторые Информация в основном только известна (без особых усилий) для внутреннего контроля.
Более того,этот пост предлагает вызватьUpdateTarget
на переплет вTextBox.Text
вCoerceValueCallback
, но, во-первых, как подразумевается выше, мой внутренний контроль не может иметь никаких знаний о текстовом поле, а во-вторых, мне, вероятно, придется позвонитьUpdateSource
сначала на привязкуValue
свойство внутреннего контроля. Я нене вижу, где это сделать, как в рамкахCoerceValue
метод, приведенное значение еще не установлено (поэтомуслишком рано, чтобы обновить привязку), в то время как в случае, если значение сбрасываетсяCoerceValue
значение свойства останется таким, каким оно было, следовательно, обратный вызов, измененный свойством, не будет вызван (как также подразумевается вэто обсуждение).
Одним из возможных обходных путей, о котором я подумал, была замена свойства зависимости вSomeControl
с обычной собственностью иINotifyPropertyChanged
реализация (так что я могу вручную вызватьPropertyChanged
событие, даже если значение было приведено). Однако это будет означать, что я больше не могу объявлять привязку к этому свойству, поэтомуне очень полезное решение.