如何拆分按标题分组的两个组,以及 C# WPF CollectionView 中的出现时间?

How to split two groups that are being grouped by title, also by time of occurrence in C# WPF CollectionView?

所以我正在利用 CollectionView 将相似的数据分组在一起。从我下面的代码中,您可以看到我有一个 class,它有一个标识符,另一个 class 其中包含时间戳、标题和消息。

因此,如果 collection 为空,并且我在 07:30:01 AM 生成标题 A,这将创建一个组。如果我在那之后立即生成,另一个标题 A 在 07:30:03 AM,那么它应该与前一个组合在一起,因为它们是相同的标题。现在,如果我在 07:30:10 AM 生成标题 B,那么它应该创建另一个组,因为现有标题和这个标题不同。如果我在那之后立即生成另一个标题 B,它将与标题 B 分组。

我的意图是,虽然我想继续根据标题对其进行分组,但如果最后一个条目是 07:30:15 AM 的标题 B,而新条目是 07:31:00 AM 的标题 A,我希望这个条目成为一个新的组,而不是将它分组到现有的标题 A 中。我可以通过标识符对其进行排序来实现这一点,您可以在下面看到:

但是如您所见,我不希望将那些 0、1、2、3 写在那里,我希望将标题分组写在那里。有办法吗?

这是我的代码:

Xaml:

<Window.Resources>
        <local:LogStatusCollection x:Key="logKey" />
        <CollectionViewSource x:Key="logCollection" Source="{DynamicResource logKey}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="TimeStamp" />
            </CollectionViewSource.SortDescriptions>
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="Identifier" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>
        <DataGrid x:Name="dataGrid1" 
                  DataContext="{DynamicResource logCollection}" ItemsSource="{Binding Path=.}"
                  CanUserAddRows="False" IsReadOnly="True" AutoGenerateColumns="False">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Time Stamp" Binding="{Binding Path=StatusLog.TimeStamp}" Width="*"/>
                <DataGridTextColumn Header="Title" Binding="{Binding Path=StatusLog.Title}" Width="*"/>
                <DataGridTextColumn Header="Message" Binding="{Binding Path=StatusLog.Message}" Width="*"/>
            </DataGrid.Columns>

            <DataGrid.GroupStyle>
                <!-- Style for groups at top level. -->
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Margin" Value="0,0,0,5"/>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <Expander IsExpanded="True" Background="#FF112255" BorderBrush="#FF002255" Foreground="#FFEEEEEE" BorderThickness="1,1,1,5">
                                            <Expander.Header>
                                                <DockPanel>
                                                    <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
                                                    <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount, StringFormat=Count: {0}}"/>
                                                </DockPanel>
                                            </Expander.Header>
                                            <Expander.Content>
                                                <ItemsPresenter />
                                            </Expander.Content>
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </DataGrid.GroupStyle>
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Foreground" Value="Black" />
                    <Setter Property="Background" Value="White" />
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>

C#:

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public LogStatusCollection logCollection { get; }                                                                                

        public MainWindow()
        {
            InitializeComponent();

            logCollection = (LogStatusCollection)this.Resources["logKey"];
            logCollection.Add(new LogStatus
            {
                Identifier = 0,
                StatusLog = new Status { Title = "Title A", Message = "Message A", TimeStamp = DateTime.Now.ToString()}
            });
            logCollection.Add(new LogStatus
            {
                Identifier = 1,
                StatusLog = new Status { Title = "Title B", Message = "Message B", TimeStamp = DateTime.Now.AddMinutes(1).ToString() }
            });
            logCollection.Add(new LogStatus
            {
                Identifier = 1,
                StatusLog = new Status { Title = "Title B", Message = "Message B", TimeStamp = DateTime.Now.AddMinutes(5).ToString() }
            });
            logCollection.Add(new LogStatus
            {
                Identifier = 2,
                StatusLog = new Status { Title = "Title A", Message = "Message A", TimeStamp = DateTime.Now.AddMinutes(7).ToString() }
            });
            logCollection.Add(new LogStatus
            {
                Identifier = 3,
                StatusLog = new Status { Title = "Title B", Message = "Message B", TimeStamp = DateTime.Now.AddMinutes(12).ToString() }
            });
            logCollection.Add(new LogStatus
            {
                Identifier = 3,
                StatusLog = new Status { Title = "Title B", Message = "Message B", TimeStamp = DateTime.Now.AddMinutes(15).ToString() }
            });

        }



    }

    public class LogStatusCollection : ObservableCollection<LogStatus> {

    }

    public class LogStatus : INotifyPropertyChanged
    {
        private int _identifier = 0;
        private Status _status;

        public int Identifier
        {
            get { return _identifier; }
            set
            {
                if (_identifier != value)
                {
                    _identifier = value;
                    NotifyPropertyChanged("Identifier");
                }
            }
        }

        public Status StatusLog
        {
            get { return _status; }
            set
            {
                if (_status != value)
                {
                    _status = value;
                    NotifyPropertyChanged("Status");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class Status : INotifyPropertyChanged
    {
        private string _timestamp;
        private string _title;
        private string _message;

        public string TimeStamp 
        {
            get { return _timestamp; }
            set 
            {
                if(_timestamp != value)
                {
                    _timestamp = value;
                    NotifyPropertyChanged("TimeStamp");
                }
            }
        }

        public string Title
        {
            get { return _title; }
            set
            {
                if (_title != value)
                {
                    _title = value;
                    NotifyPropertyChanged("Title");
                }
            }
        }

        public string Message
        {
            get { return _message; }
            set
            {
                if (_message != value)
                {
                    _message = value;
                    NotifyPropertyChanged("Message");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

不是绑定到 Name,而是绑定到 Items 的第一个元素,它们都具有相同的 Title:

<Expander.Header>
    <DockPanel>
        <TextBlock FontWeight="Bold" Text="{Binding Path=Items[0].StatusLog.Title}" Margin="5,0,0,0" Width="100"/>
        <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount, StringFormat=Count: {0}}"/>
    </DockPanel>
</Expander.Header>