UpdateSourceTrigger = WPF中的PropertyChanged和StringFormat的问题

时间:2010-07-08 03:15:01

标签: wpf converter string-formatting updatesourcetrigger

我的应用程序中有一个文本框,它是绑定到我的类中的十进制字段的数据,绑定模式是双向的。我使用StringFormat = {0:c}进行货币格式化。

只要我不触摸'UpdateSourceTrigger',这就可以正常工作。如果我设置UpdateSourceTrigger = PropertyChanged,它会停止格式化我输入的文本。

这是我的代码示例

Employee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Converter
{
    public class Employee : INotifyPropertyChanged
    {
        int _employeeNumber;
        string _firstName;
        string _lastName;
        string _department;
        string _title;
        decimal _salary;

        public Employee()
        {
            _employeeNumber = 0;
            _firstName =
                _lastName =
                _department =
                _title = null;
        }
        public int EmployeeNumber
        {
            get { return _employeeNumber; }
            set 
            { 
                _employeeNumber = value;
                OnPropertyChanged("EmployeeNumber");
            }
        }
        public string FirstName
        {
            get { return _firstName; }
            set 
            { 
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        public string LastName
        {
            get { return _lastName; }
            set 
            { 
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }

        public string Department
        {
            get { return _department; }
            set 
            { 
                _department = value;
                OnPropertyChanged("Department");
            }
        }

        public string Title
        {
            get { return _title + " salary: " + _salary.ToString(); }
            set 
            { 
                _title = value;
                OnPropertyChanged("Title");
            }
        }

        public decimal Salary
        {
            get { return _salary; }
            set
            {
                _salary = value;                
                OnPropertyChanged("Salary");
                OnPropertyChanged("Title");
            }
        }

        public override string ToString()
        {
            return String.Format("{0} {1} ({2})", FirstName, LastName, EmployeeNumber);
        }


        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
                this.PropertyChanged(this, args);
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

EmployeeList.cs:

using System.Collections.ObjectModel;

namespace Converter
{
    public class EmployeeList : ObservableCollection<Employee>
    {
    }
}

Window1.xaml:

<Window x:Class="Converter.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Converter"
    Title="Window1" Height="500" Width="500">
    <Window.Resources>
        <local:EmployeeList x:Key="myEmployeeList">
            <local:Employee EmployeeNumber="1" FirstName="John" LastName="Dow" Title="Accountant" Department="Payroll" Salary="25000.00" />
            <local:Employee EmployeeNumber="2" FirstName="Jane" LastName="Austin" Title="Account Executive" Department="Customer Management" Salary="25000.00" />
            <local:Employee EmployeeNumber="3" FirstName="Ralph" LastName="Emmerson" Title="QA Manager" Department="Product Development" Salary="25000.00" />
            <local:Employee EmployeeNumber="4" FirstName="Patrick" LastName="Fitzgerald" Title="QA Manager" Department="Product Development" Salary="25000.00" />
            <local:Employee EmployeeNumber="5" FirstName="Charles" LastName="Dickens" Title="QA Manager" Department="Product Development" Salary="25000.00" />            
        </local:EmployeeList>
        <local:StringToDecimalCurrencyConverter x:Key="StringToDecimalCurrencyConverter"></local:StringToDecimalCurrencyConverter>
    </Window.Resources>
    <Grid DataContext="{StaticResource myEmployeeList}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="240" />
            <RowDefinition Height="45" />
        </Grid.RowDefinitions>
        <ListBox Name="employeeListBox"  ItemsSource="{Binding Path=., Mode=TwoWay}" Grid.Row="0" />
        <Grid Grid.Row="1"  DataContext="{Binding ElementName=employeeListBox, Path=SelectedItem, Mode=TwoWay}">
            <Grid.RowDefinitions>
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="80" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Grid.Row="0" Grid.Column="0">First Name</Label>
            <Label Grid.Row="1" Grid.Column="0">Last Name</Label>
            <Label Grid.Row="2" Grid.Column="0">Title</Label>
            <Label Grid.Row="3" Grid.Column="0">Department</Label>
            <Label Grid.Row="4" Grid.Column="0">Salary</Label>

            <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=FirstName}" />
            <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=LastName}" />
            <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=Title}" />
            <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Mode=TwoWay,  Path=Department}" />
            <TextBox Grid.Row="4" Grid.Column="1"  Text="{Binding Mode=TwoWay, StringFormat=\{0:c\}, UpdateSourceTrigger=PropertyChanged, Path=Salary}" />
            <TextBlock Grid.Row="5" Grid.Column="1"  Text="{Binding Mode=OneWay, Converter={StaticResource StringToDecimalCurrencyConverter}, Path=Salary}" />
        </Grid>        
    </Grid>
</Window>

如果从上面的代码中删除“UpdateSourceTrigger = PropertyChanged”,它可以正常工作。

我也尝试使用Converter而不是StringFormat,但问题仍未解决。

1 个答案:

答案 0 :(得分:5)

问题是,如果您使用转换器并更改属性已更改,则WPF将忽略属性更改,同时它是更新源属性的过程。由于PropertyChanged事件是从setter引发的,因此WPF会忽略它。

这样做的原因是,如果在文本框中键入“1”,则会转换为十进制值1.0,然后转换回字符串“$ 1.00”。这将改变文本框中的文本并重置光标,因此如果您尝试键入“12”,则最终会得到“2 $ 1.00”。

请注意,您的Employee对象正在更新,问题只是TextBox没有获得新格式化的值。

如果你真的想要这种行为,你可以在绑定上设置IsAsync=True,WPF将不再将其视为可重入的更改并允许它。这在.NET 4.0中也发生了变化,因此如果您升级到最新版本的框架,那么您应该会看到您期望的行为。