Критерии WPF DataTemplateSelector изменяются, но шаблон не применяется повторно? - PullRequest
4 голосов
/ 09 мая 2011

У меня есть DataTemplateSelector, который применяется к DataGridTemplateColumn. Он правильно предоставляет мне DataTemplate, который варьируется в зависимости от определенной информации в моем DataRow (в других столбцах).

Пока все хорошо.

Однако, когда я теперь изменяю данные в своей сетке, в результате чего селектором для этого столбца будет выбран другой DataTemplate, он НЕ будет автоматически отображать этот новый DataTemplate.

Я прочитал в Pro WPF в C # 2008 Мэтью Макдональду (Апресс), стр. 564, что это известная проблема, и единственный выход - это освободить селектор и повторно применить его, что будет очень медленно, если в моей таблице много записей .

Кто-нибудь нашел способ обойти это или, может быть, в .NET4 есть новая функция, которая борется с этой проблемой?

Спасибо

Marcel

1 Ответ

3 голосов
/ 28 июня 2012

Одним из решений является размещение 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;
    }
}

Изменить: я удалил свой предыдущий ответ, который должен был использовать конвертер вместо селектора. Это сработало, но я думаю, что это лучший ответ.

...