tl; dr: Zorlanmış değerler, veri bağlamaları genelinde yayılmaz. Kod arkası, bağlamanın diğer tarafını bilmediğinde, güncellemeyi veri bağlama genelinde nasıl zorlayabilirim?Zorunlu Değerlerin Yayılımı
WPF bağımlılık özelliği üzerinde CoerceValueCallback
kullanıyorum ve bağlamaları üzerine yayılır alamadım değerleri dayatılmış konusu sıkıştım.
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
<Window x:Class="CoerceValueTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CoerceValueTest" Height="300" Width="300"
xmlns:local="clr-namespace:CoerceValueTest"
>
<StackPanel>
<local:SomeBiggerControl x:Name="sc"/>
<TextBox Text="{Binding Value, ElementName=sc, Mode=TwoWay}" Name="tb"/>
<Button Content=" "/>
</StackPanel>
</Window>
yani iki kullanıcı kontrolleri, diğer iç içe bir, ve pencerenin bulunanların dış biri . İç kullanıcı denetimi, dış kontrolün bir Value
bağımlılık özelliğine bağlı olan bir Value
bağımlılık özelliğine sahiptir. Pencerede, bir TextBox.Text
özelliği dış denetimin Value
özelliğine bağlıdır.
İç denetim, Value
özelliğine sahip bir CoerceValueCallback
özelliğine sahiptir, bunun etkisi bu Value
özelliğinin yalnızca çift sayılarla atanabilmesidir.
Bu kodun gösterim amacıyla basitleştirildiğini unutmayın. Gerçek sürüm kurucudaki hiçbir şeyi başlatmaz; İki kontrol aslında burada ilgili kurucularda yapılan her şeyi yapan kontrol şablonlarına sahiptir. Yani, gerçek kodda, dış kontrol iç kontrolü bilmiyor.
metin kutusuna çift sayıda yazma ve (metin kutusunun altındaki kukla butonuna odaklanarak mesela) odak değiştirirken, hem Value
özellikleri usulüne güncellenmektedir. Ancak, metin kutusuna tek bir sayı yazarken, iç denetimin Value
özelliği değişmez, dış denetimin Value
özelliği ve TextBox.Text
özelliği tek sayıyı gösterir.
Soruma soru: Metin kutusunda bir güncelleştirmeyi nasıl zorlayabilirim (ve ideal olarak dış denetimin Value
özelliğindeyken, biz de varız)?
an SO question on the same problem'u buldum, ama gerçekten bir çözüm sunmuyor. Değeri sıfırlamak için bir özellik değiştirilen olay işleyicisini kullanmaya itiraz eder, ancak görebildiğim kadarıyla, bu, değerlendirme kodunun dış denetime çoğaltılması anlamına gelir. Temelde bilgi sadece iç kontrolde bilinir (fazla çaba gerektirmez).
Üstelik this blogpost yukarıda ima olarak, ilk CoerceValueCallback
yılında TextBox.Text
bağlanma, ancak üzerinde UpdateTarget
çağırma önerir içimdeki kontrolü muhtemelen metin kutusu hakkında herhangi bir bilgiye sahip olamaz ve ikinci, muhtemelen ilk UpdateSource
aramak zorunda kalacaktı iç kontrolün Value
özelliğinin bağlanması üzerine.CoerceValue
yönteminde olduğu gibi, bunun nerede yapıldığını göremiyorum, kodlanmış değer henüz ayarlanmadı (bu yüzden bağlamayı güncellemek için çok erken), değer CoerceValue
tarafından sıfırlanırsa, özellik değeri, yalnızca ne olduğu kalmaya devam edecektir, dolayısıyla bir özellik değiştirilen geri arama çağrılmayacaktır (this discussion'da da belirtildiği gibi). Ben geleneksel bir özellik ve INotifyPropertyChanged
uygulaması ile SomeControl
yılında bağımlılık özelliği yerine geçecekti düşünmüştü
olası bir geçici çözüm (yani elle değeri zorla olsa bile PropertyChanged
olayı tetikleyebilir). Ancak, bu, artık bu mülk üzerinde bir bağlayıcılık beyan edemeyeceğim anlamına geliyor, bu yüzden gerçekten yararlı bir çözüm değil.
Bunun için bir cevap bulursan bana haber ver =) –