0

I have a user control, with the following (simlified) layout:

<UserControl x:Name="FV">
 <DockPanel LastChildFill="False">
  <StackPanel DockPanel.Dock="Left">
    ... some content, let's say customer name ...
  </StackPanel>
  <MyButton DockPanel.Dock="Left"
    Visibility="{Binding Path=IsMouseOver, ElementName=FV, Converter={StaticResource boolToVisibilityConverter}}">
  </MyButton>
 </DockPanel>
</UserControl>

So basically it shows a text and on hover an edit button just to the right of this text.

Now I use this control as ItemTemplate in a tree.

The problem comes with long names. In this case the tree gets a horizontal scroll and UserControl logically stretches to the right and my button is not visible anymore.

text1 (edit)  |
text22 (edit) |
vverylongtext |

I want to overlap the verylongtext on hover with my button:

text1 (edit)  |
text22 (edit) |
vverylo(edit) |

How can I achieve this? My UserControl has no knowledge of where it is used and thus no knowledge of ActualWidth of parent elements.

Ramkrishna Sharma
  • 6,961
  • 3
  • 42
  • 51
Maxim Zabolotskikh
  • 3,091
  • 20
  • 21
  • What you are saying can be done for sure. But another approach could be 1) setting `TextTrimming` property. 2) Showing Edit below the text all the time. – AnjumSKhan Sep 23 '16 at 12:04
  • Please check if my answer suits your needs. – AnjumSKhan Sep 24 '16 at 04:48
  • First, thank you for your answer. I will definitelly give it a try, but most likely towards the end of the week. This task was moved a bit down on my backlog, no time to try it out immideatelly. But I'll definitely vote it up, once tried out. – Maxim Zabolotskikh Sep 26 '16 at 09:34

2 Answers2

0

To place your button over the text you can use AdornerLayer, Z-Index, Tooltip or Popup. The last seems to me the easiest solution. Here is an example of how it can be done with popup:

<StackPanel Margin="0 20 0 0" Name="StackPanel" Width="100">
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <ScrollViewer.Resources>
            <wpfApplication1:OrConverter x:Key="OrConverter" />
        </ScrollViewer.Resources>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="longlonglonglongtextlonglonglonglongtextlonglonglonglongtext" />
            <Popup x:Name="Popup" StaysOpen="True"
                   PlacementTarget="{Binding ElementName=StackPanel}"
                   Placement="Right"
                   HorizontalOffset="-20"> <!--here you can bind to button's width instead of static value-->
                <Popup.IsOpen>
                    <MultiBinding Converter="{StaticResource OrConverter}">
                        <Binding ElementName="StackPanel" Path="IsMouseOver" Mode="OneWay" />
                        <Binding ElementName="Popup" Path="IsMouseOver" Mode="OneWay" />
                    </MultiBinding>
                </Popup.IsOpen>
                <Button Name="Button" Content="X" Height="16" Width="20" VerticalAlignment="Top" />
            </Popup>
        </StackPanel>
    </ScrollViewer>
</StackPanel>

OrConverter can be found in this answer.

And it looks like this.

Community
  • 1
  • 1
3615
  • 3,787
  • 3
  • 20
  • 35
  • My edit-button was already internally implemented as a pop-up. The thing is, the width of the tree is not fixed, like in your example, and tree gets a horizontal scroll. So pop-up is appearing alright, but outside of the scrollviewer's visible area.. – Maxim Zabolotskikh Sep 28 '16 at 09:38
  • I'm not sure I undestand about which 'width of the tree' you are talking about. Do you mean Width that I set on StackPanel? Well, that was put just to emulate horizontal scroll, it should work fine without that width. I've added video with how my example behaves locally, but It would be nice to have an actual reproduction of your problem. – 3615 Sep 28 '16 at 09:52
  • I looked at the video. The difference is, that I cannot actually access "StackPanel" from the popup. My user control starts where your second (inner) stackpanel is. This user control ideally has no knowledge where it is put to (and it's actually used in many places, one of them, the problematic one, in a tree). So my PlacementTarget is actually the tree, but the UC doesn't event know it's in a tree. – Maxim Zabolotskikh Sep 28 '16 at 11:31
  • Then I tried to pass PlacementTarget as DependencyProperty. This kind of places it correct horizontally if I bind to tree, but also puts it on top-right corner of the tree, not tree item. Binding it to TreeViewItem also doesn't work, beacuse TreeViewItem is always wide, so popup appears right of the tree, as if the part of the TreeViewItem hidden by scroll were there. – Maxim Zabolotskikh Sep 28 '16 at 11:31
0

I did it exactly according to your requirement. I created a UserControl with a TextBlock and Button. If text in TextBlock is very long, Button remains out of sight, which upon MouseOver comes int sight exactly as you need. However, if text in TextBlock remains small enough, Button remains in sight.

Note : HorizontalAlignment = Left must be set on the Button.

Window3.xaml

<Window x:Class="WpfStackOverflow.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:uc="clr-namespace:WpfStackOverflow"
        Title="Window3" Height="300" Width="300" SizeToContent="WidthAndHeight">

    <StackPanel>
        <uc:UserControl1 Width="200" Height="35"/>
    </StackPanel>

</Window>

UserControl.1.xaml

<UserControl x:Class="WpfStackOverflow.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:local="clr-namespace:WpfStackOverflow"
             Background="Bisque"
             Height="25">       

    <StackPanel x:Name="DckPnl" Height="25" Orientation="Horizontal">
        <TextBlock x:Name="Tb" MouseEnter="Tb_MouseEnter_1" MouseLeave="Tb_MouseLeave_1" FontFamily="Arial" Text="some content , let's say customer name some content, let's say customer name" Background="AliceBlue"/>
        <Button x:Name="Btn" Visibility="Hidden" Content="Edit" Width="35" Height="25" Margin="0 0 0 0" HorizontalAlignment="Left"/>
    </StackPanel>

</UserControl>

UserControl1.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfStackOverflow
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void Tb_MouseEnter_1(object sender, MouseEventArgs e)
        {
            Thickness newMargin = new Thickness();

            FormattedText f = new FormattedText(Tb.Text,
                                                new System.Globalization.CultureInfo("en-US"),
                                                System.Windows.FlowDirection.LeftToRight,
                                                new Typeface("Arial"),
                                                Tb.FontSize, Brushes.Black);
            if (f.Width > this.ActualWidth)
                newMargin = new Thickness((this.ActualWidth - f.Width) - Btn.ActualWidth, 0, 0, 0);
            else
                newMargin = Btn.Margin;

            Btn.Margin = newMargin;
            Btn.Visibility = System.Windows.Visibility.Visible;
        }

        private void Tb_MouseLeave_1(object sender, MouseEventArgs e)
        {
            Btn.Margin = new Thickness(0, 0, 0, 0);
            Btn.Visibility = System.Windows.Visibility.Hidden;
        }
    }   
}
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38
  • f.Width will never be greater than this.ActualWidth. TreeViewItem is hidden under the scroll, so its ActualWidth is not visible part, but the total width of the item. – Maxim Zabolotskikh Sep 28 '16 at 12:12