WPF DataTemplateSelector 标准更改但模板未重新应用?

发布于 2024-11-06 04:05:28 字数 413 浏览 6 评论 0原文

我有一个应用于 DataGridTemplateColumn 的 DataTemplateSelector。 它正确地为我提供了一个 DataTemplate,该模板根据我的 DataRow(在其他列中)中的某些信息而变化。

到目前为止,一切都很好。

但是,当我现在更改网格中的数据时,这将导致选择器为该列选择不同的 DataTemplate,它不会自动显示这个新的 DataTemplate。

我在 Matthew MacDonald (Apress) 的 Pro WPF in C# 2008 第 564 页中读到,这是已知问题,唯一的解决方法是释放选择器并重新应用它,当我的表中有很多记录时,这会非常慢。

有没有人找到解决这个问题的方法,或者也许在 .NET4 中有一个新功能可以解决这个问题?

谢谢马塞尔

I have a DataTemplateSelector which is applied to a DataGridTemplateColumn.
It is correctly providing me with a DataTemplate that varies depending on certain information in my DataRow (in other columns).

So far so good.

However, when I now alter data in my grid which would cause a different DataTemplate to be chosen by the selector for that column it does NOT automatically show this new DataTemplate.

I read in Pro WPF in C# 2008 by Matthew MacDonald (Apress) page 564 that this is known issue and the only way around is to release the Selector and reapply this which would be very slow when there are many records in my table.

Has anyone found a way around this or maybe in .NET4 there is a new feature that combats this issue?

Thanks

Marcel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫性小仙女 2024-11-13 04:05:28

一种解决方案是将 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;
    }
}

编辑:我已经删除了我之前的答案,即使用转换器而不是选择器。这确实有效,但我认为这是一个更好的答案。

One solution is to put a ContentPresenter inside the cell. That way when the content changes the ContentPresenter will request the template from the selector again. eg:

<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>

and code behind:

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;
    }
}

Edit: I have removed my previous answer which was to use a converter instead of a selector. That did work but I think this is a better answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文