WPF DataGrid,在 header 和行之间添加一个标签
WPF DataGrid, add a lable between header and rows
当数据网格中有一些关于数据的通知时,我想如下图所示。
这在 windows 中作为通知很常见,但在控件内部并不常见。我认为 WPF 应该能够通过使用控件模板来执行此操作,但我对这个主题还不是很有经验。我需要直接跳入这些内容,所以我需要 Datagrid 模板的基础知识。
此处 post 的解决方案假装只是最终解决方案的起点,而不是完整的解决方案。
要实现您的目标,您必须开始研究 DataGrid
风格,正如您已经指出的那样。
如 this post, you might get the Style by using Expression Blend 中所述或查看默认的 Microsoft 样式。
我这里选了第二个,为了有一个清晰的例子。因此,我将以下代码基于代码 posted Microsoft Docs。请注意,此处的代码可能与原始 Microsoft Controls 代码略有不同,如上文 post 中所述。
在post输入完整代码之前,让我们看看结果如何:
这里的 NOTIFICATION BAR
只是一个带有 hard-coded 内容的 Label
-> 这是自定义通知栏(颜色、绑定、可见性等)的起点。 .) 根据您的要求,您的第一个 post 不是很清楚。
如您所见,在默认 Datagrid
中有一个不可见的渐变,正如我解释的那样,Microsoft 网站上的样式 posted 可能与默认的略有不同。
完整代码很长,所以我post编辑了它here。
为了帮助浏览代码,请注意我刚刚在主 Grid
中添加了一个 Row
(请在第 225 行找到一个战利品)和上面提到的第 251 行中的 Label
。
您不能单独使用控件模板来完成此操作。控件模板定义控件的外观和状态。在您的情况下,您添加了需要一些代码的功能。您可以使用附加属性、触发器和改编的控件模板来解决此问题,但编写自定义控件似乎更合适。
编写自定义控件可能会非常复杂,因此我将重点关注您问题的简单解决方案。我假设您希望一次显示一个通知。但是,以下解决方案也很容易扩展以支持 collection 通知。
首先,我创建了一个派生自 DataGrid
的自定义控件。它为通知的可见性、其文本和关闭按钮文本提供依赖属性。它还公开了一个 RoutedUICommand
并注册了一个绑定到它的命令。它将用于关闭通知。
[TemplatePart(Name = NotificationBorderPart, Type = typeof(Border))]
[TemplatePart(Name = NotificationTextBlockPart, Type = typeof(TextBlock))]
[TemplatePart(Name = NotificationButtonPart, Type = typeof(Button))]
public class NotifyingDataGrid : DataGrid
{
private const string NotificationBorderPart = "PART_NotificationBorder";
private const string NotificationTextBlockPart = "PART_NotificationTextBlock";
private const string NotificationButtonPart = "PART_NotificationButton";
static NotifyingDataGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NotifyingDataGrid), new FrameworkPropertyMetadata());
}
public static readonly RoutedUICommand Dismiss = new RoutedUICommand("Dismisses a notification", "Dismiss", typeof(NotifyingDataGrid));
public static readonly DependencyProperty NotificationVisibilityProperty = DependencyProperty.Register(
nameof(NotificationVisibility), typeof(Visibility), typeof(NotifyingDataGrid), new PropertyMetadata(Visibility.Collapsed));
public static readonly DependencyProperty NotificationTextProperty = DependencyProperty.Register(
nameof(NotificationText), typeof(string), typeof(NotifyingDataGrid), new PropertyMetadata(string.Empty, OnNotificationTextChanged));
public static readonly DependencyProperty DismissTextProperty = DependencyProperty.Register(
nameof(DismissText), typeof(string), typeof(NotifyingDataGrid), new PropertyMetadata("Dismiss"));
public NotifyingDataGrid()
{
CommandBindings.Add(new CommandBinding(Dismiss, OnDismiss));
}
public Visibility NotificationVisibility
{
get => (Visibility)GetValue(NotificationVisibilityProperty);
set => SetValue(NotificationVisibilityProperty, value);
}
public string NotificationText
{
get => (string)GetValue(NotificationTextProperty);
set => SetValue(NotificationTextProperty, value);
}
public string DismissText
{
get => (string)GetValue(DismissTextProperty);
set => SetValue(DismissTextProperty, value);
}
private void OnDismiss(object sender, ExecutedRoutedEventArgs e)
{
NotificationVisibility = Visibility.Collapsed;
}
private static void OnNotificationTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var notifyingDataGrid = (NotifyingDataGrid)d;
notifyingDataGrid.NotificationVisibility = Visibility.Visible;
}
}
我使用 Blend 创建了原始控件模板的副本。我用代表通知 header 的 Border
控件扩展了它。其中有一个TextBlock
和一个Button
。 Text
属性绑定到我们的 parent 自定义数据网格的依赖属性。按钮的命令使用Dismiss
命令,由我们的命令绑定来处理
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" SnapsToDevicePixels="True"/>
<Polygon x:Name="Arrow" Fill="Black" HorizontalAlignment="Right" Margin="8,8,3,3" Opacity="0.15" Points="0,10 10,10 10,0" Stretch="Uniform" VerticalAlignment="Bottom"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="Arrow" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:NotifyingDataGrid}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="#FF688CAF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NotifyingDataGrid}">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<Border x:Name="PART_NotificationBorder" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="1" Background="Yellow" Visibility="{Binding NotificationVisibility, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="PART_NotificationTextBlock" Grid.Column="0" Text="{Binding NotificationText, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}" FontStyle="Italic" Foreground="Gray" TextTrimming="CharacterEllipsis"/>
<Button x:Name="PART_NotificationButton" Grid.Column="1" BorderThickness="0" Background="Yellow" TextBlock.FontStyle="Italic" TextBlock.FontWeight="Bold" TextBlock.Foreground="Gray" Content="{Binding DismissText, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}" Command="local:NotifyingDataGrid.Dismiss"/>
</Grid>
</Border>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.Row="2"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="2" ViewportSize="{TemplateBinding ViewportHeight}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</Style.Triggers>
</Style>
你现在可以绑定通知文本和关闭按钮文本,以及通知可见性,当你想从视图模型中隐藏它时,它会派上用场。
<local:NotifyingDataGrid ItemsSource="{Binding MyItems}"
NotificationText="{Binding MyNotificationText}"
DismissText="{Binding MyDismissText}"/>
请注意,我在这里定义了模板部件,尽管它们并没有被直接使用。这是因为我想专注于使用绑定的简单解决方案。正如您在控件的控件模板中看到的那样,通知 header 控件嵌套在 ScrollViewer
的另一个控件模板中,它们不能像通常在自定义中那样被 GetTemplateChild
访问控制。因此,将此解决方案作为起点。
如果你想显示多个通知,你可以很容易地调整这个控件。您将公开包含所有通知文本的 collection 类型的依赖项 属性。在控件模板中,您可以放置一个 ItemsControl
作为绑定到此 collection 的通知 header。要像以前一样显示每个项目,您可以将 DataTemplate
添加为 ItemTemplate
,其中包含 Border
、TextBlock
和 Button
。将当前项目作为 CommandParameter
传递,以便您可以访问和关闭焦点通知。
当数据网格中有一些关于数据的通知时,我想如下图所示。
这在 windows 中作为通知很常见,但在控件内部并不常见。我认为 WPF 应该能够通过使用控件模板来执行此操作,但我对这个主题还不是很有经验。我需要直接跳入这些内容,所以我需要 Datagrid 模板的基础知识。
此处 post 的解决方案假装只是最终解决方案的起点,而不是完整的解决方案。
要实现您的目标,您必须开始研究 DataGrid
风格,正如您已经指出的那样。
如 this post, you might get the Style by using Expression Blend 中所述或查看默认的 Microsoft 样式。
我这里选了第二个,为了有一个清晰的例子。因此,我将以下代码基于代码 posted Microsoft Docs。请注意,此处的代码可能与原始 Microsoft Controls 代码略有不同,如上文 post 中所述。
在post输入完整代码之前,让我们看看结果如何:
这里的 NOTIFICATION BAR
只是一个带有 hard-coded 内容的 Label
-> 这是自定义通知栏(颜色、绑定、可见性等)的起点。 .) 根据您的要求,您的第一个 post 不是很清楚。
如您所见,在默认 Datagrid
中有一个不可见的渐变,正如我解释的那样,Microsoft 网站上的样式 posted 可能与默认的略有不同。
完整代码很长,所以我post编辑了它here。
为了帮助浏览代码,请注意我刚刚在主 Grid
中添加了一个 Row
(请在第 225 行找到一个战利品)和上面提到的第 251 行中的 Label
。
您不能单独使用控件模板来完成此操作。控件模板定义控件的外观和状态。在您的情况下,您添加了需要一些代码的功能。您可以使用附加属性、触发器和改编的控件模板来解决此问题,但编写自定义控件似乎更合适。
编写自定义控件可能会非常复杂,因此我将重点关注您问题的简单解决方案。我假设您希望一次显示一个通知。但是,以下解决方案也很容易扩展以支持 collection 通知。
首先,我创建了一个派生自 DataGrid
的自定义控件。它为通知的可见性、其文本和关闭按钮文本提供依赖属性。它还公开了一个 RoutedUICommand
并注册了一个绑定到它的命令。它将用于关闭通知。
[TemplatePart(Name = NotificationBorderPart, Type = typeof(Border))]
[TemplatePart(Name = NotificationTextBlockPart, Type = typeof(TextBlock))]
[TemplatePart(Name = NotificationButtonPart, Type = typeof(Button))]
public class NotifyingDataGrid : DataGrid
{
private const string NotificationBorderPart = "PART_NotificationBorder";
private const string NotificationTextBlockPart = "PART_NotificationTextBlock";
private const string NotificationButtonPart = "PART_NotificationButton";
static NotifyingDataGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NotifyingDataGrid), new FrameworkPropertyMetadata());
}
public static readonly RoutedUICommand Dismiss = new RoutedUICommand("Dismisses a notification", "Dismiss", typeof(NotifyingDataGrid));
public static readonly DependencyProperty NotificationVisibilityProperty = DependencyProperty.Register(
nameof(NotificationVisibility), typeof(Visibility), typeof(NotifyingDataGrid), new PropertyMetadata(Visibility.Collapsed));
public static readonly DependencyProperty NotificationTextProperty = DependencyProperty.Register(
nameof(NotificationText), typeof(string), typeof(NotifyingDataGrid), new PropertyMetadata(string.Empty, OnNotificationTextChanged));
public static readonly DependencyProperty DismissTextProperty = DependencyProperty.Register(
nameof(DismissText), typeof(string), typeof(NotifyingDataGrid), new PropertyMetadata("Dismiss"));
public NotifyingDataGrid()
{
CommandBindings.Add(new CommandBinding(Dismiss, OnDismiss));
}
public Visibility NotificationVisibility
{
get => (Visibility)GetValue(NotificationVisibilityProperty);
set => SetValue(NotificationVisibilityProperty, value);
}
public string NotificationText
{
get => (string)GetValue(NotificationTextProperty);
set => SetValue(NotificationTextProperty, value);
}
public string DismissText
{
get => (string)GetValue(DismissTextProperty);
set => SetValue(DismissTextProperty, value);
}
private void OnDismiss(object sender, ExecutedRoutedEventArgs e)
{
NotificationVisibility = Visibility.Collapsed;
}
private static void OnNotificationTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var notifyingDataGrid = (NotifyingDataGrid)d;
notifyingDataGrid.NotificationVisibility = Visibility.Visible;
}
}
我使用 Blend 创建了原始控件模板的副本。我用代表通知 header 的 Border
控件扩展了它。其中有一个TextBlock
和一个Button
。 Text
属性绑定到我们的 parent 自定义数据网格的依赖属性。按钮的命令使用Dismiss
命令,由我们的命令绑定来处理
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" SnapsToDevicePixels="True"/>
<Polygon x:Name="Arrow" Fill="Black" HorizontalAlignment="Right" Margin="8,8,3,3" Opacity="0.15" Points="0,10 10,10 10,0" Stretch="Uniform" VerticalAlignment="Bottom"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="Arrow" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:NotifyingDataGrid}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="#FF688CAF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NotifyingDataGrid}">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<Border x:Name="PART_NotificationBorder" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="1" Background="Yellow" Visibility="{Binding NotificationVisibility, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="PART_NotificationTextBlock" Grid.Column="0" Text="{Binding NotificationText, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}" FontStyle="Italic" Foreground="Gray" TextTrimming="CharacterEllipsis"/>
<Button x:Name="PART_NotificationButton" Grid.Column="1" BorderThickness="0" Background="Yellow" TextBlock.FontStyle="Italic" TextBlock.FontWeight="Bold" TextBlock.Foreground="Gray" Content="{Binding DismissText, RelativeSource={RelativeSource AncestorType={x:Type local:NotifyingDataGrid}}}" Command="local:NotifyingDataGrid.Dismiss"/>
</Grid>
</Border>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.Row="2"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="2" ViewportSize="{TemplateBinding ViewportHeight}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</Style.Triggers>
</Style>
你现在可以绑定通知文本和关闭按钮文本,以及通知可见性,当你想从视图模型中隐藏它时,它会派上用场。
<local:NotifyingDataGrid ItemsSource="{Binding MyItems}"
NotificationText="{Binding MyNotificationText}"
DismissText="{Binding MyDismissText}"/>
请注意,我在这里定义了模板部件,尽管它们并没有被直接使用。这是因为我想专注于使用绑定的简单解决方案。正如您在控件的控件模板中看到的那样,通知 header 控件嵌套在 ScrollViewer
的另一个控件模板中,它们不能像通常在自定义中那样被 GetTemplateChild
访问控制。因此,将此解决方案作为起点。
如果你想显示多个通知,你可以很容易地调整这个控件。您将公开包含所有通知文本的 collection 类型的依赖项 属性。在控件模板中,您可以放置一个 ItemsControl
作为绑定到此 collection 的通知 header。要像以前一样显示每个项目,您可以将 DataTemplate
添加为 ItemTemplate
,其中包含 Border
、TextBlock
和 Button
。将当前项目作为 CommandParameter
传递,以便您可以访问和关闭焦点通知。