views:

447

answers:

3

I'm working on a link control in WPF which fits the text with icon links case in the Windows UX Guide. What I want is to have some text within a hyperlink that appears to the right of some image.

In my case I started off by using a TextBlock that contained a Hyperlink which then contained my image and some text.

<TextBlock>
        <Hyperlink>
            <Rectangle Height="16"
                       Width="16"
                       Fill="{StaticResource MyIconBrush}"
                       Stretch="UniformToFill"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Left" />
            <Run>My link text</Run>
        </Hyperlink>
</TextBlock>

The problem with this however was that the image being taller than my text produced an effect where the text was aligned to the bottom. Unfortunately I haven't found any way to control the vertical alignment within the TextBlock or within the Hyperlink so I've resorted to attempting an alternative layout where the Hyperlink and the Rectangle that represent my vector icon are separated in order to get them to align properly like shown below.

<StackPanel Orientation="Horizontal">
    <Rectangle Height="16"
               Width="16"
               Fill="{StaticResource MyIconBrush}"
               Stretch="UniformToFill"
               VerticalAlignment="Center"
               HorizontalAlignment="Left" />
    <TextBlock VerticalAlignment="Center"><Hyperlink>My link text<Hyperlink></TextBlock>
</StackPanel>

The problem with this however is that now that my Icon and my Hyperlink are separated I don't get my MouseOver appearance of my link when I the mouse is over my icon and vise-versa. Also my Hyperlink has an option for me to hook up a Command but the Rectangle and StackPanel do not so if I make use Hyperlink.Command the icon will not execute the Command.

So this got me to thinking, how do I simulate MouseOver for a given control such with a checkbox where you get the MouseOver effect on the box when you actually mouse over it's associated text. I know in the HTML world the label element has a for attribute that can be used to specify which control it is labeling which will basically do what I'm looking for. Also I can imagine that in other scenarios it may be nice to have a label that when you mouse over shows a corresponding text box as if the mouse is over it and possibly when clicked focus is given to the corresponding text box as well. For now though I'm interested mainly in how to to get a label or label like element in WPF to act as a proxy for a given control in terms of it's MouseOver state. Also I would like to do this purely in XAML if possible.

UPDATE: I also attempted the following but no success. I get the appearance I want but the link under the icon did not appear to be enough to get the mouse events. I guess the hit tests only work when the mouse is actually over the rendered text regardless of the padding of the control.

<Grid>
    <Rectangle Height="16"
               Width="16"
               Fill="{StaticResource MyIconBrush}"
               Stretch="UniformToFill"
               HorizontalAlignment="Left"
               VerticalAlignment="Center"
               IsHitTestVisible="False"
               Focusable="False"/>
    <TextBlock Padding="18,0,0,0"
                VerticalAlignment="Center"><Hyperlink>Configure additional filters...</Hyperlink></TextBlock>
</Grid>
+1  A: 

The first code is the way to go. You can control the Run alignment with BaselineAlignment. Set it to Center and your link will behave as you wanted.

Julien Lebosquain
This does solve my original problem related to alignment but I noticed that after implementing it this way that my icon also gets underlined and even worse the underline is broken between the text and the image. I think I'll have to find a different strategy where the fundamental question still remains, how to simulate a MouseOver in WPF.
jpierson
+1  A: 

Using Run and BaselineAlignment="Center" will result in a broken link. Just stuff the image and textblock in a horizontal stack panel like this.

<TextBlock> 
    <Hyperlink> 
        <StackPanel Orientation="Horizontal">
            <Rectangle 
                Height="16" Width="16" 
                Fill="{StaticResource MyIconBrush}" 
                Stretch="UniformToFill" VerticalAlignment="Center" HorizontalAlignment="Left" /> 
            <TextBlock 
                Text="My link text" 
                VerticalAlignment="Center"/>
        </StackPanel>
    </Hyperlink>
</TextBlock>

If you want a control to visible react to a mouseover event in some other way than it does by default you need to override its controltemplate. This is easiest done by taking an existing controltemplate and modify it to your needs. For example, a control template for checkbox can be found here: http://msdn.microsoft.com/en-us/library/ms752319(v=VS.85).aspx The link should how to change the background to another color on mouseover but you could also make a line under some content change color to simulate a hyperlink.

Wallstreet Programmer
Ah, by broken link you must mean a broken underline. I seen this as well once I tried out the suggestion by Julien Lebosquain.
jpierson
I realize that I can do this be redefining the template however that type of solution always seems way to heavyweight for what I'm after. I simply want to control the MouseOver state of a control without having to mouse over the control or at least trigger the same reactive mechanisms that would normally take place on MouseOver without having to redefine the template of that control. If MouseOver was not readonly the solution would be very straightforward however I can understand why this is not the case.
jpierson
+1  A: 

UI elements have a RaiseEvent method you can use to simulate mouse events.

XAML:

<Window x:Class="MouseOverTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <StackPanel>
        <TextBlock>  
            <Hyperlink MouseEnter="OnHyperlinkMouseEnter" Name="_hyperLink">  
                <TextBlock Text="My link text" /> 
            </Hyperlink> 
        </TextBlock>
        <Button Content="Simulate mouse enter" Click="OnButtonClick" />
    </StackPanel>
</Window>

Code behind:

using System.Windows;
using System.Windows.Input;

namespace MouseOverTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            MouseEventArgs mouseEventArgs = new MouseEventArgs(Mouse.PrimaryDevice, 0);
            mouseEventArgs.RoutedEvent = Mouse.MouseEnterEvent;
            _hyperLink.RaiseEvent(mouseEventArgs);
        }

        private void OnHyperlinkMouseEnter(object sender, MouseEventArgs e)
        {
            MessageBox.Show("Mouse enter");
        }
    }
}
Wallstreet Programmer
Neat! Not pure XAML but this is so far the closest to what I was really after.
jpierson