WPF中UpdateSourceTrigger = PropertyChanged和StringFormat的问题 [英] Problem with UpdateSourceTrigger=PropertyChanged and StringFormat in WPF

查看:124
本文介绍了WPF中UpdateSourceTrigger = PropertyChanged和StringFormat的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中有一个文本框,该文本框将数据绑定到类中的小数字段,并且绑定方式为两种方式.我正在使用StringFormat = {0:c}进行货币格式设置.

I have a text box in my application which is data bound to a decimal field in my class and the binding mode is two way. I am using StringFormat={0:c} for currency formatting.

只要我不触摸"UpdateSourceTrigger",此方法就可以正常工作.如果设置UpdateSourceTrigger = PropertyChanged,它将停止格式化我输入的文本.

This works fine as long as I don't touch 'UpdateSourceTrigger'. If I set UpdateSourceTrigger=PropertyChanged , It stops formatting the text that I am entering.

这是我的代码示例

Employee.cs

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:

EmployeeList.cs:

using System.Collections.ObjectModel;

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

Window1.xaml:

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",则效果很好.

If you remove 'UpdateSourceTrigger=PropertyChanged' from the above code it works fine.

我也尝试使用Converter而不是StringFormat,但问题仍然没有解决.

I have also tried using Converter instead of the StringFormat, and still the problem is not solved.

推荐答案

问题是,如果您使用转换器对属性更改进行更新,则WPF在更新源属性的过程中将忽略属性更改.由于从设置器引发了PropertyChanged事件,因此WPF将忽略它.

The problem is that if you use a converter and update on property changed then WPF will ignore property changes while it is the process of updating the source property. Since the PropertyChanged event is raised from the setter, WPF ignores it.

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

The reason it does this is that if you typed "1" in the text box, this would get converted to the decimal value 1.0 and then get converted back to the string "$1.00". This would change the text in the text box and reset the cursor, so if you tried to type "12" you'd end up with "2$1.00".

请注意,您的Employee对象正在更新,问题仅在于TextBox没有获得新格式的值.

Note that your Employee object is getting updated, and the problem is just that the TextBox isn't getting a newly formatted value.

如果您确实希望该行为,可以在绑定上设置IsAsync=True,WPF将不再将其视为可重入更改,并将允许它.在.NET 4.0中,这也已更改,因此,如果您升级到最新版本的框架,则应该会看到预期的行为.

If you really do want that behavior, you can set IsAsync=True on the binding and WPF will no longer see it as a reentrant change and will allow it. This has also changed in .NET 4.0, so if you upgrade to the latest version of the framework then you should see the behavior you expect.

这篇关于WPF中UpdateSourceTrigger = PropertyChanged和StringFormat的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆