先放出图片:

大体情况就如 Demo 上的说明,我再详述一下:
该 Demo 内容为一个实现了 INotifyPropertyChanged 接口的数据类的属性与文本框的内容进行双向绑定。属性的 setter 中设置了逻辑,将一个大于25的数值赋给属性时,属性将它自动修正为25,然后希望它将这一修正反馈给文本框。然而它执行得不是很好,请注意红色方框:myText 控件的 Text 属性被正确的修正为25,然而控件上显示出来的内容却没有得到修正,也就是说,这种情况下文本框的显示值与 Text 属性不一致!这是一个 BUG 吗?
根据多次试验,证明这个问题的重现条件是:当前 myText.Text 的值是25。重现方法是:在 myText 中填入一个大于25的数值。重现结果是:myText 显示的是大于25的输入数值,但 myText.Text 是25。
我希望能够以以下方案之一解决该问题:
1.找到方法,使显示值与 Text 保证保持一致。
2.找到方法,使得当我任意指定一个 FrameworkElement 和它的 DependencyProperty 后,能在该依赖项属性改变时收到通知,这样我就能方便的实现自己的数据绑定机制。
Demo 内容如下:(人生中第一篇博文,不知道如何上传文件,只有粘贴代码上来了-_-)
XAML:
<Window x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<Label DockPanel.Dock="Left">myText</Label>
<TextBox Name="myText" />
</DockPanel>
<DockPanel DockPanel.Dock="Bottom">
<Label DockPanel.Dock="Left">myText.Text 和 md.MyInt</Label>
<Label BorderBrush="Black" BorderThickness="1" Name="theText"></Label>
</DockPanel>
<Label DockPanel.Dock="Top">
<TextBlock TextWrapping="Wrap">
该 Demo 展示我的杯具:
myText 的 Text 属性被绑定到 MyData 对象的 MyInt 属性上,
该属性的 setter 逻辑中限制它超出范围时会自动修正为上限,
我希望当我在 myText 输入内容时这一机制会自动生效。
但实际上,当你在初始的5后面输入1时,只有第一次生效(将51修正为25),
之后就变成251、2511、25111……
而你点击按钮却会发现,myText.Text 和 md.MyInt 都是正确的值,
只有显示值是错误的,意味着 myText 控件上显示的并不是它的 Text 值。
程序输出中可以看到每次输入后通过绑定发送给 md.MyInt 的值确实就是 myText 控件上显示的值。
搞笑的是,输入内容大于 int 类型上限后,会自动调用默认的验证器:myText 边框变红,却并不阻止继续输入。
</TextBlock>
</Label>
<Button DockPanel.Dock="Top" Height="30" Width="200" Click="ShowText">显示 myText.Text 和 md.MyInt</Button>
<Button Height="30" Width="200" Click="SetText25">执行 myText.Text=25</Button>
<Button Height="30" Width="200" Click="SetText2">执行 myText.Text=2</Button>
</DockPanel>
</Window>
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Demo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private MyData md;
public MainWindow()
{
InitializeComponent();
md = new MyData(5);
//绑定
myText.SetBinding(TextBox.TextProperty, new Binding("MyInt") { Mode = BindingMode.TwoWay, Source = md, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
}
/// <summary>
/// 三个按钮执行的操作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ShowText(object sender,RoutedEventArgs e)
{
theText.Content = "myText.Text:" + myText.Text + "; md.MyInt:" + md.MyInt;
}
private void SetText25(object sender,RoutedEventArgs e)
{
myText.Text = "25";
}
private void SetText2(object sender,RoutedEventArgs e)
{
myText.Text = "2";
}
}
/// <summary>
/// 数据类
/// </summary>
public class MyData : System.ComponentModel.INotifyPropertyChanged
{
private int _myint;
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public MyData(int m)
{
_myint = m;
}
/// <summary>
/// setter 器中包含的逻辑使输入值超出上限时自动修正为上限
/// </summary>
public int MyInt
{
get { return _myint; }
set
{
_myint = Math.Min(value, 25);
Console.WriteLine("myText 绑定给 md.MyInt 的值:" + value);
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("MyInt"));
}
}
}
}
谢谢大虾小虾来参与讨论和提出方案
浙公网安备 33010602011771号