在 Cell Click 上对 DataGrid 进行排序后调用 WPF Multiple Converter
WPF Multiple Converter calls after sorting DataGrid on Cell Click
https://github.com/milanmilas/WPFDataGridSortingColorConverter
我的 DataGrid 上有一个 BackgroundColor 转换器,每个单元格调用一次:
Converter Called: Ana , 25
Converter Called: Ana , 25
Converter Called: Dan , 5
Converter Called: Dan , 5
Converter Called: Mike , 65
Converter Called: Mike , 65
DataGrid 在更新其中一个单元格值 ("just for testing") 的每个单元格上都有 Click 事件。每次单击单元格时,转换器将触发 3 次,但只要我通过单击名称 header 订购网格行,它就会触发多次,就像排序后创建重复的单元格一样:
Age Incremented
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
<Window.Resources>
<local:SimpleBrushColorConverter x:Key="SimpleColorConverter" />
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding People}" SelectionUnit="CellOrRowHeader" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" IsReadOnly="True" SortMemberPath="Age">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Name" Text="{Binding Path=Name, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Age" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Age" Text="{Binding Path=Age, Mode=TwoWay}" Background="{Binding Path=Age, Converter={ StaticResource SimpleColorConverter}}" MouseLeftButtonDown="OnCellMouseLeftButtonDown"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
public partial class MainWindow : Window
{
PeopleViewModel vm = new PeopleViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = vm;
}
private void OnCellMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("");
Debug.WriteLine("Age Incremented");
vm.People.First().Age++;
}
}
public class SimpleBrushColorConverter : IValueConverter
{
public object Convert(object values, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("Simple Converter Called: " + values + " , " + values);
if ((int)values < 18) return new SolidColorBrush(Color.FromRgb(250, 0, 0));
if (60 > (int)values && (int)values > 18) return new SolidColorBrush(Color.FromRgb(0, 250, 0));
return new SolidColorBrush(Color.FromRgb(0, 0, 250));
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class PeopleViewModel
{
public ObservableCollection<Person> People { get; set; }
public ObservableCollection<Person> People2 { get; set; }
public PeopleViewModel()
{
People = new ObservableCollection<Person>(
new List<Person>
{
new Person() {Age = 5, Name = "Dan"},
new Person() {Age = 25, Name = "Ana"},
new Person() {Age = 65, Name = "Mike"}
}
);
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Person : NotifyPropertyChanged
{
private string _name;
private int _age;
public string Name
{
get { return _name; }
set { _name = value;
OnPropertyChanged();
}
}
public int Age
{
get { return _age; }
set { _age = value;
OnPropertyChanged();
}
}
}
如果我使用 MultiValueConverter 并也绑定到 TextBlock,在排序并单击单元格后的转换器中,我可以看到第一个 Converter 调用是针对具有 "IsVisible =False" 的旧值的 TextBlock。第二次调用是针对真正的可见单元格。再次排序将为旧值之一添加带有 "IsVisible=False" 的附加 TextBlock。这会持续到 10 个 TextBlock。在某些时候,一些 TextBlock 会被回收,因此它们不再出现在转换器调用中。
将在转换器中使用 "IsVisible" 来区分有效的 TextBlock,但仍然不确定为什么会这样?
public class MultiBrushColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("Simple Converter Called: " + values[0] + " , " + values[0]);
var textBlock = values[1];
if ((int)values[0] < 18) return new SolidColorBrush(Color.FromRgb(250, 0, 0));
if (60 > (int)values[0] && (int)values[0] > 18) return new SolidColorBrush(Color.FromRgb(0, 250, 0));
return new SolidColorBrush(Color.FromRgb(0, 0, 250));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<DataGridTemplateColumn Header="Age" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Age" Text="{Binding Path=Age}" MouseLeftButtonDown="OnCellMouseLeftButtonDown">
<TextBlock.Background>
<MultiBinding Converter="{StaticResource MultiColorConverter}">
<Binding Path="Age" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</TextBlock.Background>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
https://github.com/milanmilas/WPFDataGridSortingColorConverter
我的 DataGrid 上有一个 BackgroundColor 转换器,每个单元格调用一次:
Converter Called: Ana , 25
Converter Called: Ana , 25
Converter Called: Dan , 5
Converter Called: Dan , 5
Converter Called: Mike , 65
Converter Called: Mike , 65
DataGrid 在更新其中一个单元格值 ("just for testing") 的每个单元格上都有 Click 事件。每次单击单元格时,转换器将触发 3 次,但只要我通过单击名称 header 订购网格行,它就会触发多次,就像排序后创建重复的单元格一样:
Age Incremented
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
Converter Called: Dan , 10
<Window.Resources>
<local:SimpleBrushColorConverter x:Key="SimpleColorConverter" />
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding People}" SelectionUnit="CellOrRowHeader" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" IsReadOnly="True" SortMemberPath="Age">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Name" Text="{Binding Path=Name, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Age" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Age" Text="{Binding Path=Age, Mode=TwoWay}" Background="{Binding Path=Age, Converter={ StaticResource SimpleColorConverter}}" MouseLeftButtonDown="OnCellMouseLeftButtonDown"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
public partial class MainWindow : Window
{
PeopleViewModel vm = new PeopleViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = vm;
}
private void OnCellMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("");
Debug.WriteLine("Age Incremented");
vm.People.First().Age++;
}
}
public class SimpleBrushColorConverter : IValueConverter
{
public object Convert(object values, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("Simple Converter Called: " + values + " , " + values);
if ((int)values < 18) return new SolidColorBrush(Color.FromRgb(250, 0, 0));
if (60 > (int)values && (int)values > 18) return new SolidColorBrush(Color.FromRgb(0, 250, 0));
return new SolidColorBrush(Color.FromRgb(0, 0, 250));
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class PeopleViewModel
{
public ObservableCollection<Person> People { get; set; }
public ObservableCollection<Person> People2 { get; set; }
public PeopleViewModel()
{
People = new ObservableCollection<Person>(
new List<Person>
{
new Person() {Age = 5, Name = "Dan"},
new Person() {Age = 25, Name = "Ana"},
new Person() {Age = 65, Name = "Mike"}
}
);
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Person : NotifyPropertyChanged
{
private string _name;
private int _age;
public string Name
{
get { return _name; }
set { _name = value;
OnPropertyChanged();
}
}
public int Age
{
get { return _age; }
set { _age = value;
OnPropertyChanged();
}
}
}
如果我使用 MultiValueConverter 并也绑定到 TextBlock,在排序并单击单元格后的转换器中,我可以看到第一个 Converter 调用是针对具有 "IsVisible =False" 的旧值的 TextBlock。第二次调用是针对真正的可见单元格。再次排序将为旧值之一添加带有 "IsVisible=False" 的附加 TextBlock。这会持续到 10 个 TextBlock。在某些时候,一些 TextBlock 会被回收,因此它们不再出现在转换器调用中。
将在转换器中使用 "IsVisible" 来区分有效的 TextBlock,但仍然不确定为什么会这样?
public class MultiBrushColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("Simple Converter Called: " + values[0] + " , " + values[0]);
var textBlock = values[1];
if ((int)values[0] < 18) return new SolidColorBrush(Color.FromRgb(250, 0, 0));
if (60 > (int)values[0] && (int)values[0] > 18) return new SolidColorBrush(Color.FromRgb(0, 250, 0));
return new SolidColorBrush(Color.FromRgb(0, 0, 250));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<DataGridTemplateColumn Header="Age" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Name="Age" Text="{Binding Path=Age}" MouseLeftButtonDown="OnCellMouseLeftButtonDown">
<TextBlock.Background>
<MultiBinding Converter="{StaticResource MultiColorConverter}">
<Binding Path="Age" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</TextBlock.Background>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>