Критерии WPF DataTemplateSelector изменяются, но шаблон не применяется повторно?
У меня есть DataTemplateSelector, который применяется к DataGridTemplateColumn. Он правильно предоставляет мне DataTemplate, который варьируется в зависимости от определенной информации в моем DataRow (в других столбцах).
Все идет нормально.
Однако, когда я теперь изменяю данные в своей сетке, что приведет к выбору другого DataTemplate селектором для этого столбца, он НЕ будет автоматически показывать этот новый DataTemplate.
Я прочитал в Pro WPF в C# 2008 Мэтью Макдональду (Апресс), стр. 564, что это известная проблема, и единственный выход - это выпустить селектор и повторно применить его, что будет очень медленно, если в моей таблице много записей.
Кто-нибудь нашел способ обойти это или, возможно, в.NET4 есть новая функция, которая борется с этой проблемой?
Спасибо
завивать волосы щипцами
1 ответ
Одним из решений является размещение ContentPresenter внутри ячейки. Таким образом, при изменении содержимого ContentPresenter снова запросит шаблон у селектора. например:
<Window
x:Class="TestSAS.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"
xmlns:local="clr-namespace:TestSAS">
<Window.Resources>
<local:MySelector x:Key="mySelector">
<local:MySelector.UpperTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="upper - "></TextBlock>
<TextBlock Text="{Binding}"></TextBlock>
</StackPanel>
</DataTemplate>
</local:MySelector.UpperTemplate>
<local:MySelector.LowerTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="lower - "></TextBlock>
<TextBlock Text="{Binding}"></TextBlock>
</StackPanel>
</DataTemplate>
</local:MySelector.LowerTemplate>
</local:MySelector>
</Window.Resources>
<DockPanel>
<Button DockPanel.Dock="Bottom" Click="doit_Click">Do It</Button>
<DataGrid Name="mainGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding FirstName}" ContentTemplateSelector="{StaticResource mySelector}"></ContentPresenter>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</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;
using System.ComponentModel;
namespace TestSAS
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
mainGrid.ItemsSource = "Bob,mary,frank,George".Split(',').Select(s => new Person() { FirstName = s }).ToArray();
}
private void doit_Click(object sender, RoutedEventArgs e)
{
((Person[])mainGrid.ItemsSource)[2].FirstName = "Frank";
}
}
public class MySelector : DataTemplateSelector
{
public DataTemplate UpperTemplate { get; set; }
public DataTemplate LowerTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var st = item as string;
if (st == null) return null;
if (st.Substring(0, 1).ToString().ToLower() == st.Substring(0, 1).ToString()) return LowerTemplate;
return UpperTemplate;
}
}
public class Person : INotifyPropertyChanged
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Изменить: я удалил свой предыдущий ответ, который должен был использовать конвертер вместо селектора. Это сработало, но я думаю, что это лучший ответ.