在 WPF 中使用 DataTrigger 时的绑定问题

发布于 2024-12-01 10:53:14 字数 799 浏览 3 评论 0原文

我的 WPF 项目中的绑定存在问题。相关的 XAML 如下:

<dg:DataGrid.RowDetailsTemplate>
    <DataTemplate>
      <StackPanel>
        <TextBlock Name="txtnoitems" Text="No Records Found" Visibility="Collapsed"></TextBlock>
      </StackPanel>
      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="False">
          <Setter  TargetName="txtnoitems" Property="Visibility" Value="Visible"></Setter>
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </dg:DataGrid.RowDetailsTemplate>

我想做的是当 DataGrid.HasItemsfalse 时显示 TextBlock。由于某种原因这不起作用。

谁能看到我的问题可能是什么?

I'm having an issue with the bindings in my WPF project. The relevant XAML is below:

<dg:DataGrid.RowDetailsTemplate>
    <DataTemplate>
      <StackPanel>
        <TextBlock Name="txtnoitems" Text="No Records Found" Visibility="Collapsed"></TextBlock>
      </StackPanel>
      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="False">
          <Setter  TargetName="txtnoitems" Property="Visibility" Value="Visible"></Setter>
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </dg:DataGrid.RowDetailsTemplate>

What I am trying to do is have the TextBlock appear when the DataGrid.HasItems is false. This doesn't work for some reason.

Can anyone see what my issue might be?

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

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

发布评论

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

评论(1

再见回来 2024-12-08 10:53:14

根据评论中的假设进行编辑:

如果正如 @bathineni 提到的,当集合中不存在任何项目时,您希望在 DataGrid 上显示一个框,您可能需要使用除了 RowDetailsTemplate 以外的机制来实现此目的。

我能想到的两个示例是设置 DataGrid 的样式,使其包含突出显示的 TextBlock 来显示此消息,另一个示例是创建一个包含 DataGrid 和要在顶部显示的消息的网格。

示例一:
设置 DataGrid 样式

您可以找到 这是非常好的教程,它将向您展示如何设计 DataGrid 内部的样式,类似于 Samuel 在这里的样式,总共有四个。

在 DataGrid 模板中,将所有内容包围在 Grid 对象中并创建要在其中显示的消息。

例如:(请原谅较长的代码片段)

        <Style TargetType="{x:Type DataGrid}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGrid}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition />
                            </Grid.RowDefinitions>

                            <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        SnapsToDevicePixels="True"
                        Grid.Row="1"
                        Padding="{TemplateBinding Padding}">
                                <ScrollViewer Focusable="false" Name="DG_ScrollViewer">
                                    <ScrollViewer.Template>
                                        <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="Auto"/>
                                                    <RowDefinition Height="*"/>
                                                    <RowDefinition Height="Auto"/>
                                                </Grid.RowDefinitions>

                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="Auto"/>
                                                    <ColumnDefinition Width="*"/>
                                                    <ColumnDefinition Width="Auto"/>
                                                </Grid.ColumnDefinitions>

                                                <!--Left Column Header Corner -->
                                                <Button
                                                    Style="{StaticResource selectAllButtonTemplate}"
                                                    Command="{x:Static DataGrid.SelectAllCommand}"
                                                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
                                                    Focusable="false"
                                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}" />

                                                <!--Column Headers-->
                                                <Primitives:DataGridColumnHeadersPresenter 
                                                    Grid.Column="1"
                                                    Name="PART_ColumnHeadersPresenter"
                                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>

                                                <!--DataGrid content-->
                                                <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />

                                                <Border Name="noItemsBorder" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden" SnapsToDevicePixels="True" Background="Coral" BorderBrush="DarkRed" BorderThickness="1" Grid.Row="1" Grid.ColumnSpan="2">
                                                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="No items to display" Margin="20" />
                                                </Border>

                                                <ScrollBar
                                                    Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Name="PART_VerticalScrollBar"
                                                    Orientation="Vertical"
                                                    Maximum="{TemplateBinding ScrollableHeight}"
                                                    ViewportSize="{TemplateBinding ViewportHeight}"
                                                    Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                    Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>

                                                <Grid Grid.Row="2" Grid.Column="1">
                                                    <Grid.ColumnDefinitions>
                                                        <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
                                                        <ColumnDefinition Width="*"/>
                                                    </Grid.ColumnDefinitions>
                                                    <ScrollBar 
                                                        Grid.Column="1"
                                                        Name="PART_HorizontalScrollBar"
                                                        Orientation="Horizontal"
                                                        Maximum="{TemplateBinding ScrollableWidth}"
                                                        ViewportSize="{TemplateBinding ViewportWidth}"
                                                        Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                        Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                                                </Grid>
                                            </Grid>

                                            <ControlTemplate.Triggers>
                                                <DataTrigger Binding="{Binding Path=HasItems, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Value="False">
                                                    <Setter TargetName="noItemsBorder" Property="Visibility" Value="Visible" />
                                                </DataTrigger>
                                            </ControlTemplate.Triggers>
                                        </ControlTemplate>
                                    </ScrollViewer.Template>
                                    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                </ScrollViewer>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}">Transparent</SolidColorBrush>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}">Transparent</SolidColorBrush>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}">Black</SolidColorBrush>
            </Style.Resources>

            <Style.Triggers>
                <Trigger Property="IsGrouping" Value="true">
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                </Trigger>
            </Style.Triggers>
        </Style>

在上面的示例中,您可以看到 noItemsBorder 对象,它只是覆盖了 ScrollContentPresenter x:Name="当 DataGrid.HasItems 为 false(通过使用触发器显示)时,PART_ScrollContentPresenter" 对象,另一种方法是在 Visibility 属性上使用 Binding,但为了方便起见为清楚起见,我根据您的问题使用了触发器。

示例二:
一次性 TextBlock 覆盖

这与上面的示例类似,但您无需修改​​ DataGrid 样式,而只需将两个控件封装在 Grid 内。

虽然这可行,但需要将此代码复制并粘贴到您想要使用它的任何地方,这并不理想。

代码如下:

    <Grid>
        <DataGrid Name="dg" ItemsSource="{Binding Path=DisplayItems}" />

        <Border HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding ElementName=dg, Path=HasItems, Converter={StaticResource booleanToVisibilityConverter}}" SnapsToDevicePixels="True" Background="Coral" BorderBrush="DarkRed" BorderThickness="1">
            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="No items to display" Margin="20" />
        </Border>
    </Grid>

原始帖子:

我不确定您的 HasItems 使用什么,但请确保它是引发适当的 PropertyChanged 事件的属性。

此代码按我的预期工作:

DataGrid XAML

    <DataGrid Name="dataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=TextToDisplay}" />
        </DataGrid.Columns>

        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Name="txtnoitems" Text="No Records Found" Visibility="Collapsed"></TextBlock>
                </StackPanel>

                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding HasItems}" Value="False">
                        <Setter  TargetName="txtnoitems" Property="Visibility" Value="Visible"></Setter>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>

(注意:我还删除了触发器绑定中的 {RelativeSource},并将 RowDetailsVisibilityMode 属性设置为DataGrid)

某些项目类 (用作子项目)

public class SomeItem : INotifyPropertyChanged
{
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #region HasItems Definition

    private bool _HasItems = true;

    public bool HasItems
    {
        get
        {
            return _HasItems;
        }
        set
        {
            _HasItems = value;
            OnPropertyChanged("HasItems");
        }
    }

    #endregion // end of HasItems region
    #region TextToDisplay Definition

    private string _TextToDisplay = null;

    public string TextToDisplay
    {
        get
        {
            return _TextToDisplay;
        }
        set
        {
            _TextToDisplay = value;
            OnPropertyChanged("TextToDisplay");
        }
    }

    #endregion // end of TextToDisplay region

    public SomeItem(string blah)
    {
        TextToDisplay = blah;
    }
}

用法:

        dataGrid.Items.Add(new SomeItem("items"));
        dataGrid.Items.Add(new SomeItem("items"));
        dataGrid.Items.Add(new SomeItem("not items") { HasItems = false });
        dataGrid.Items.Add(new SomeItem("items"));

Edit as per assumption in comments:

If as @bathineni mentioned you wanted to display a box over the DataGrid when no items were present in the collection, you would probably need to use a mechanism other than the RowDetailsTemplate to acheive this.

Two example I can think of would be to style the DataGrid so that it contained a highlighted TextBlock to display this message, and the other would be to create a grid which contained the DataGrid and the Message you wanted to display on top.

Example One:
Style the DataGrid

You can find a very nice tutorial here that will show you how to style the DataGrid internals similar to how Samuel has here, there are four of these in total.

In the DataGrid Template, surround everything in a Grid object and create the message to be displayed within.

For Example: (please excuse the long code snippet)

        <Style TargetType="{x:Type DataGrid}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGrid}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition />
                            </Grid.RowDefinitions>

                            <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        SnapsToDevicePixels="True"
                        Grid.Row="1"
                        Padding="{TemplateBinding Padding}">
                                <ScrollViewer Focusable="false" Name="DG_ScrollViewer">
                                    <ScrollViewer.Template>
                                        <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="Auto"/>
                                                    <RowDefinition Height="*"/>
                                                    <RowDefinition Height="Auto"/>
                                                </Grid.RowDefinitions>

                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="Auto"/>
                                                    <ColumnDefinition Width="*"/>
                                                    <ColumnDefinition Width="Auto"/>
                                                </Grid.ColumnDefinitions>

                                                <!--Left Column Header Corner -->
                                                <Button
                                                    Style="{StaticResource selectAllButtonTemplate}"
                                                    Command="{x:Static DataGrid.SelectAllCommand}"
                                                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
                                                    Focusable="false"
                                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}" />

                                                <!--Column Headers-->
                                                <Primitives:DataGridColumnHeadersPresenter 
                                                    Grid.Column="1"
                                                    Name="PART_ColumnHeadersPresenter"
                                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>

                                                <!--DataGrid content-->
                                                <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />

                                                <Border Name="noItemsBorder" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden" SnapsToDevicePixels="True" Background="Coral" BorderBrush="DarkRed" BorderThickness="1" Grid.Row="1" Grid.ColumnSpan="2">
                                                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="No items to display" Margin="20" />
                                                </Border>

                                                <ScrollBar
                                                    Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Name="PART_VerticalScrollBar"
                                                    Orientation="Vertical"
                                                    Maximum="{TemplateBinding ScrollableHeight}"
                                                    ViewportSize="{TemplateBinding ViewportHeight}"
                                                    Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                    Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>

                                                <Grid Grid.Row="2" Grid.Column="1">
                                                    <Grid.ColumnDefinitions>
                                                        <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
                                                        <ColumnDefinition Width="*"/>
                                                    </Grid.ColumnDefinitions>
                                                    <ScrollBar 
                                                        Grid.Column="1"
                                                        Name="PART_HorizontalScrollBar"
                                                        Orientation="Horizontal"
                                                        Maximum="{TemplateBinding ScrollableWidth}"
                                                        ViewportSize="{TemplateBinding ViewportWidth}"
                                                        Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                        Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                                                </Grid>
                                            </Grid>

                                            <ControlTemplate.Triggers>
                                                <DataTrigger Binding="{Binding Path=HasItems, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Value="False">
                                                    <Setter TargetName="noItemsBorder" Property="Visibility" Value="Visible" />
                                                </DataTrigger>
                                            </ControlTemplate.Triggers>
                                        </ControlTemplate>
                                    </ScrollViewer.Template>
                                    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                </ScrollViewer>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}">Transparent</SolidColorBrush>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}">Transparent</SolidColorBrush>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}">Black</SolidColorBrush>
            </Style.Resources>

            <Style.Triggers>
                <Trigger Property="IsGrouping" Value="true">
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                </Trigger>
            </Style.Triggers>
        </Style>

In the above example, you can see the noItemsBorder object, this just overlays the ScrollContentPresenter x:Name="PART_ScrollContentPresenter" object when DataGrid.HasItems is false (displayed by using a trigger), another way would be to use a Binding on the Visibility property, but for the sake of clarity I have used a Trigger as per your question.

Example Two:
One-use TextBlock overlay

This will be similar to the example above, but rather than modifying the DataGrid style, you would just encapsulate the two controls inside of a Grid.

Although this will work, this code will need to be copy and pasted everywhere you want to use it which is not ideal.

Code as below:

    <Grid>
        <DataGrid Name="dg" ItemsSource="{Binding Path=DisplayItems}" />

        <Border HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding ElementName=dg, Path=HasItems, Converter={StaticResource booleanToVisibilityConverter}}" SnapsToDevicePixels="True" Background="Coral" BorderBrush="DarkRed" BorderThickness="1">
            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="No items to display" Margin="20" />
        </Border>
    </Grid>

Original Post:

I'm not sure what you're using for your HasItems, but make sure it is a property which raises the appropriate PropertyChanged event.

This code works as expected for me:

DataGrid XAML

    <DataGrid Name="dataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=TextToDisplay}" />
        </DataGrid.Columns>

        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Name="txtnoitems" Text="No Records Found" Visibility="Collapsed"></TextBlock>
                </StackPanel>

                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding HasItems}" Value="False">
                        <Setter  TargetName="txtnoitems" Property="Visibility" Value="Visible"></Setter>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>

(note: that I have also removed the {RelativeSource} in the trigger binding, and set the RowDetailsVisibilityMode property to the DataGrid)

Some Item Class (used as the child items)

public class SomeItem : INotifyPropertyChanged
{
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #region HasItems Definition

    private bool _HasItems = true;

    public bool HasItems
    {
        get
        {
            return _HasItems;
        }
        set
        {
            _HasItems = value;
            OnPropertyChanged("HasItems");
        }
    }

    #endregion // end of HasItems region
    #region TextToDisplay Definition

    private string _TextToDisplay = null;

    public string TextToDisplay
    {
        get
        {
            return _TextToDisplay;
        }
        set
        {
            _TextToDisplay = value;
            OnPropertyChanged("TextToDisplay");
        }
    }

    #endregion // end of TextToDisplay region

    public SomeItem(string blah)
    {
        TextToDisplay = blah;
    }
}

Usage:

        dataGrid.Items.Add(new SomeItem("items"));
        dataGrid.Items.Add(new SomeItem("items"));
        dataGrid.Items.Add(new SomeItem("not items") { HasItems = false });
        dataGrid.Items.Add(new SomeItem("items"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文