【问题标题】:Binding issue when using a DataTrigger in WPF在 WPF 中使用 DataTrigger 时的绑定问题
【发布时间】:2011-11-03 09:19:02
【问题描述】:

我的 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。由于某种原因,这不起作用。

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

【问题讨论】:

  • 输出窗口抛出了哪些绑定错误?
  • 我也没有收到任何错误
  • 您是否在数据触发器中尝试过Value="false" 而不是Value="False"?你应该为Value="true"添加一个额外的触发器来折叠文本块
  • 欢迎来到 Stackoverflow。请选择一个合适的标题来概括问题(例如“在 DataTrigger 中绑定到 DataGrid 的 HasItems 属性”),而不是仅仅重复标签。

标签: .net wpf xaml data-binding datagrid


【解决方案1】:

根据 cmets 中的假设进行编辑:

如果像@bathineni 提到的那样,当集合中没有项目时,您想在DataGrid 上显示一个框,您可能需要使用RowDetailsTemplate 以外的机制来实现这一点。

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

示例一: 为 DataGrid 设置样式

您可以找到very nice tutorial here,它将向您展示如何设置 DataGrid 内部的样式,类似于 Samuel 在这里的样式,总共有四个。

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

例如:(请原谅长码sn-p)

        <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 对象,这只是在DataGrid.HasItems 为false 时覆盖ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 对象(使用触发器显示),另一种方法是在可见性上使用绑定属性,但为了清楚起见,我根据您的问题使用了触发器。


示例二: 一次性 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)

Some Item Class (用作子项)

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"));

【讨论】:

  • 没关系,你可以正常绑定。只需将 DataGrid 上的 ItemsSource 属性绑定到 IEnumerable(最好是 IObservableCollection&lt;T&gt;)即可显示项目。我的Items.Add 代码只是一个让演示运行的快速示例。
  • @fatty 这很重要..您正在示例中创建“HasItems”属性。但 karteek 想在数据触发器中使用 datagrid 的 HasItems 属性。创建新属性没有任何意义,因为我们已经在数据网格级别拥有相同的信息。
  • @bathineni:我也是这样阅读他的原始代码的,但假设我错了,因为他在 RowDetails 模板中使用了这个,这需要至少一行才有用?还是我弄错了?
  • @Fatty 你是对的..他正在尝试使用 rowdetailstemplate 和 HasItems 属性... rowdetailstemplate 至少需要一行来显示模板..
猜你喜欢
  • 2013-06-04
  • 2016-06-18
  • 2017-02-16
  • 2013-07-10
  • 2012-05-25
  • 2012-12-06
  • 2014-09-09
  • 1970-01-01
  • 2012-01-09
相关资源
最近更新 更多