Home > Blockchain >  How to force WPF textboxes contents to be displayed above other controls similar to excel cells
How to force WPF textboxes contents to be displayed above other controls similar to excel cells

Time:07-03

I have a listView that contains a textbox for each binding item and I want to allow overlaying text box content if its content is wider than the textbox width similar to excel cells overlaying behavior. Is there a way to do this?

1

<ListView ItemsSource="{Binding Path=MyStringCollection}">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" Width="100"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}" TextWrapping="WrapWithOverflow"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

CodePudding user response:

You can use tooltip for that. You just need to bind the source with itself.

<ListView ItemsSource="{Binding Path=MyStringCollection}">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" Width="100"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}" TextWrapping="WrapWithOverflow" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

For further information:

DrawToolTip Event

Set ToolTipSize

CodePudding user response:

To replicate a similar behavior, you can make use of a Popup.

To implement a similar behavior, you first must disable content wrapping of your TextBox.
Then replace the current TextBox with a TextBlock, which is used to display the text.
The Popup, which actually contains the editable TextBox, will then overlay this TextBlock at the exact position, thus hiding the TextBlock to make it appear to stretch and overlay the adjacent items.
A MultiTrigger will close the Popup as soon as the focus moved outside the ListBoxItem.

To improve performance you should use the VirtualizingStackPanel as items host.

<ListView ItemsSource="{Binding MyStringCollection}"
          HorizontalAlignment="Left"
          Width="800">
  <ListView.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>
  </ListView.ItemsPanel>

  <ListView.ItemTemplate>
    <DataTemplate>
      <Grid>
        <Border BorderThickness="1"
                BorderBrush="Gray">
          <TextBlock Text="{Binding}" />
        </Border>
        <Popup x:Name="EditableTextSiteHost"
               PlacementTarget="{Binding ElementName=TextSite}"
               Placement="Relative"
               Height="{Binding ElementName=TextSite, Path=ActualHeight}"
               AllowsTransparency="True"
               FocusManager.FocusedElement="{Binding ElementName=EditableTextSite}">
          <TextBox x:Name="EditableTextSite"
                   Text="{Binding TextData}" />
        </Popup>
      </Grid>

      <DataTemplate.Triggers>
        <MultiDataTrigger>
          <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}"
                       Value="True" />
            <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsKeyboardFocusWithin}"
                       Value="True" />
          </MultiDataTrigger.Conditions>
          <Setter TargetName="EditableTextSiteHost"
                  Property="IsOpen"
                  Value="True" />
        </MultiDataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ListView.ItemTemplate>

  <ListView.ItemContainerStyle>
    <Style TargetType="ListBoxItem">

      <!-- Make items overlap -->
      <Setter Property="Margin"
              Value="-2,0,0,0" />
      <Setter Property="Padding"
              Value="0" />
      <Setter Property="Width"
              Value="50" />

      <Style.Triggers>

        <!-- Apply zero Margin on the first item -->
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}"
                     Value="{x:Null}">
          <Setter Property="Margin"
                  Value="0,0,0,0" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </ListView.ItemContainerStyle>
</ListView>

To-do

This is just a raw example, a proof of concept. You would have to improve the behavior. For example, you would want to close the Popup when the user scrolls or moves the Window. Otherwise, since Popup itself is a Window, the Popup would not move to follow the placement target. You could move the related logic to an attached behavior.
You likely also want to improve the selection behavior. Currently the selection highlight border does not (virtually) extend to surround the Popup. You have to mimic this by applying a Border on the TextBox that will replicate the ListBoxItem highlight border.

  • Related