我的 WPF 桌面应用程序提供了一个 UI 来搜索人员并在 DataGrid 中显示结果。
此外,用户可以在运行时更改语言(Current(UI)Culture)。
XAML 中的 DataGrid 定义是
<DataGrid Name="SearchResultTable" AutoGenerateColumns="False" MinHeight="200" CanUserSortColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="lastName" Binding="{Binding LastName}" SortDirection="Ascending" IsReadOnly="True" DisplayIndex="0"/>
<DataGridTextColumn Header="firstName" Binding="{Binding FirstName}" IsReadOnly="True" DisplayIndex="1"/>
<DataGridTextColumn Header="dateOfBirth" Binding="{Binding DateOfBirth }" IsReadOnly="True" DisplayIndex="2"/>
</DataGrid.Columns>
</DataGrid>
DateOfBirth 列内容的格式应根据所选语言而定。
c# 代码部分是:
DataGridTextColumn col = (DataGridTextColumn)SearchResultTable.Columns[2];
col.Binding.StringFormat = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern;
此代码部分在创建 UI 类之后以及每次用户选择不同的语言时执行。
只要用户没有执行填充 DataGrid 的搜索,这种方法就可以正常工作。
但是一旦 DataGrid 第一次被填充
IList<Person> searchResult = // read data from database
SearchResultTable.ItemsSource = searchResult;
并且用户选择不同的语言会引发以下异常:
Binding cannot be changed after it has been used
那么,如何在运行时动态更改 DataGrid String 列格式呢?
EDIT
根据mm8的回答,我可以实施如下解决方案:
由于我可能不会更改 Person 类(业务领域!),因此我创建了一个以 Person 作为参考的辅助类
public class PersonHelper : INotifyPropertyChanged
{
// ...
private Person person = null;
public String LastName { get => person.getLastName(); set => person.setLastName(LastName); }
// ...
public string FormattedDateOfBirth => DateOfBirth.ToShortDateString();
public void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// ...
}
在UI类Search方法中:
PersonObsColl = new ObservableCollection<PersonHelper>();
foreach (Person p in searchResult)
{
PersonHelper ph = new PersonHelper(p);
ph.PropertyChanged += new PropertyChangedEventHandler(PropertyFormattedDateOfBirthChanged);
PersonObsColl.Add(ph);
}
在 CurrentUICulture 更改时调用的 UI 类方法中
foreach (PersonHelper ph in PersonObsColl)
ph.OnPropertyChanged("FormattedDateOfBirth");
以及 UI 类中的 Handler
private void PropertyFormattedDateOfBirthChanged(object sender, PropertyChangedEventArgs e)
{
if (sender is PersonHelper && e.PropertyName.Equals("FormattedDateOfBirth"))
{
// avoid to call invalidation for every search result line; can this be improved ?
if(PersonObsColl.IndexOf((PersonHelper)sender) == PersonObsColl.Count -1)
SearchResultTable.InvalidateVisual();
}
}