如何拆分按标题分组的两个组,以及 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>
所以我正在利用 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>