Is there a way to simulate MouseOver in WPF?
I'm working on a link control in WPF which fits the text with icon links case in the Windows UX Guide. I want 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开发者_如何学Go was aligned to the bottom. Unfortunately I haven't found a 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 of 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 its 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 its 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>
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.
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");
}
}
}
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 in CheckBox ControlTemplate Example. This should show 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.
精彩评论