开发者

Binding issue when using a DataTrigger in WPF

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&开发者_如何学Pythongt;
        </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?


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜