简体   繁体   中英

WPF C# Statusbar label content from current control's tooltip

Ok, so I'm trying to figure out how to set a status bars label text to show information about the current control that a mouse is hovering over. I have seen this numerous times on many programs so I know it can be done and I'm sure there are explanations out there that could help me but I can't seem to find the right words to search for the answer unfortunately... The closest thing I could find was in the link below. I tried to utilize this but it gave me an error when I tried to set the text property.

Anyone have some information or a link to help me by chance? Thanks, Ryan

Display text in a label when hovering over a control without using events

My XAML Code:

<StatusBar>
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="75" />
                        </Grid.ColumnDefinitions>

                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem Grid.Column="0">
                <Label Content="New Lead Inquiry" />
            </StatusBarItem>
            <Separator Grid.Column="1" Style="{StaticResource StylingStatusBarSeparator}" />
            <StatusBarItem Grid.Column="2">
                <Label x:Name="infoStatusBar" Content="Label for text about the currently hovered item" />
            </StatusBarItem>
            <Separator Grid.Column="3" Style="{StaticResource StylingStatusBarSeparator}" />
            <StatusBarItem Grid.Column="4">
                <Label Content="Not Saved" />
            </StatusBarItem>
        </StatusBar>

You can wire the MouseEnter and MouseLeave commands on your controls to set a HelpText property in your viewmodel, and then bind the status bar label to HelpText so that when it is set to something new, the new value appears in the status bar.

This answer uses the MVVM Light toolkit, but should be adaptable for any MVVM setup:

In XAML:

<Window x:Class="MvvmLightPlayground.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ignore="http://www.galasoft.ch/ignore"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d ignore"
        Height="300"
        Width="600"
        Title="MVVM Light Application">


    <Window.DataContext>
        <Binding Path="Main" Source="{StaticResource Locator}" />
    </Window.DataContext>

    <StackPanel>
        <Label Content="This is Label1" x:Name="Label1">
            <!-- Triggers like this are easy to wire up using blend.  If you do it manually, add the i: definition to your window tag as shown above -->
            <i:Interaction.Triggers>
                <i:EventTrigger SourceName="Label1" EventName="MouseEnter">
                    <i:InvokeCommandAction Command="{Binding MouseEnter}" CommandParameter="This is Label1.  Look how neat it is!" />
                </i:EventTrigger>
                <i:EventTrigger SourceName="Label1" EventName="MouseLeave">
                    <i:InvokeCommandAction Command="{Binding MouseLeave}" CommandParameter="This is Label1.  Look how neat it is!" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Label>
        <Label Content="This is Label2" x:Name="Label2">
            <i:Interaction.Triggers>
                <i:EventTrigger SourceName="Label2" EventName="MouseEnter">
                    <i:InvokeCommandAction Command="{Binding MouseEnter}" CommandParameter="This is Label2.  It's a different label." />
                </i:EventTrigger>
                <i:EventTrigger SourceName="Label2" EventName="MouseLeave">
                    <i:InvokeCommandAction Command="{Binding MouseLeave}" CommandParameter="This is Label2.  It's a different label." />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Label>

        <StatusBar>
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem>
                <Label Content="{Binding HelpText, Mode=OneWay}" /> <!-- Bind to your HelpText property in the VM -->
            </StatusBarItem>
        </StatusBar>
    </StackPanel>
</Window>

In your viewmodel:

First, add properties for your HelpText and your ICommands:

private string _helpText = "Testing";
public string HelpText
{
    get
    {
        return _helpText;
    }
    set
    {
        Set(() => HelpText, ref _helpText, value);
    }
}

private ICommand _mouseEnter;
public ICommand MouseEnter
{
    get
    {
        return _mouseEnter;
    }
    set
    {
        Set(() => MouseEnter, ref _mouseEnter, value);
    }
}

private ICommand _mouseLeave;
public ICommand MouseLeave
{
    get
    {
        return _mouseLeave;
    }
    set
    {
        Set(() => MouseLeave, ref _mouseLeave, value);
    }
}

Then initialize your ICommands in your viewmodel constructor to point at methods in the viewmodel:

public MainViewModel()
{
    MouseEnter = new RelayCommand<string>(SetHelpText);
    MouseLeave = new RelayCommand<string>(ClearHelpText);
}

Then create your helper methods to set the HelpText property:

public void SetHelpText(string helpText)
{
    HelpText = helpText;
}

public void ClearHelpText(string textToClear)
{
    // check to see whether it has already been set to something else by another MouseEnter event...
    if (HelpText == textToClear)
    {
        HelpText = "";
    }
}

This is the running sample shown with the mouse hovered over Label2 :

屏幕截图

Here's a solution that doesn't require you to modify each child control or use any frameworks.

This isn't really related to MVVM, since it's pure UI stuff. There's nothing here that would involve a viewmodel.

Handle Window.PreviewMouseMove:

MainWindow.xaml

<Window 
    ...
    PreviewMouseMove="Window_PreviewMouseMove"
    >

MainWindow.xaml.cs

Define a dependency property of type Object, and in the preview mousemove handler, give it the nearest parent tooltip of the control the mouse is over:

    private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        var element = Mouse.DirectlyOver as FrameworkElement;

        HoverToolTip = GetTooltip(element);  
    }

    #region HoverToolTip Property
    public object HoverToolTip
    {
        get { return (object)GetValue(HoverToolTipProperty); }
        set { SetValue(HoverToolTipProperty, value); }
    }

    public static readonly DependencyProperty HoverToolTipProperty =
        DependencyProperty.Register(nameof(HoverToolTip), typeof(object), typeof(MainWindow),
            new PropertyMetadata(null));
    #endregion HoverToolTip Property

    protected static Object GetTooltip(FrameworkElement obj)
    {
        if (obj == null)
        {
            return null;
        }
        else if (obj.ToolTip != null)
        {
            return obj.ToolTip;
        }
        else
        {
            return GetTooltip(VisualTreeHelper.GetParent(obj) as FrameworkElement);
        }
    }

And bind that to whatever in the XAML.

    <Label
        x:Name="StatusBar"
        Content="{Binding HoverToolTip, RelativeSource={RelativeSource AncestorType=Window}}"
        Grid.Row="2"
        />

That Label is just the quickie I put in my test XAML. This binding is the important part there:

{Binding HoverToolTip, RelativeSource={RelativeSource AncestorType=Window}}

If you're willing to settle for fewer style points, you can do it without the dependency property or the binding:

MainWindow.xaml

    <Label
        x:Name="StatusBarLabel"
        Grid.Row="2"
        />

MainWindow.xaml.cs

    private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        var element = Mouse.DirectlyOver as FrameworkElement;

        StatusBarLabel.Content = GetTooltip(element);  
    }

    protected static Object GetTooltip(FrameworkElement obj)
    {
        if (obj == null)
        {
            return null;
        }
        else if (obj.ToolTip != null)
        {
            return obj.ToolTip;
        }
        else
        {
            return GetTooltip(VisualTreeHelper.GetParent(obj) as FrameworkElement);
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM