2

Have a navigation command which needs to display a tooltip on click, while disabled, so that the user knows why it's disabled. The problem I'm having is I have no idea how to pass the TouchDown event from my xaml file to my viewmodel. Is there some way to bind this rather than creating an event in the command.xaml.cs?

Command is structured as follows. I have a single CommandButton.xaml and CommandButton.xaml.cs while everything to set up the button is handled by the VM (text, image, command executed etc) code as an example below.

<Button Focusable="True" Name="Btn1" Command="{Binding CommandToExecute}" Tag="{Binding Text}" Foreground="{x:Null}" Style="{DynamicResource ButtonStyle}" ToolTipService.ShowOnDisabled="true" TouchDown="Btn1_OnTouchDown" >
    <Button.ToolTip>
        <StackPanel>
            <TextBlock>Test</TextBlock>
            <TextBlock>Load stencil, or not your choice.</TextBlock>
        </StackPanel>
    </Button.ToolTip>
    <shellModule:AutoGreyableImage  Source="{Binding Image}" />
</Button>

As for the code behind, I have that split with the majority of the handler stuff in a base command class as follows.

public abstract class BaseCommand : BindableBase
{
    protected IModuleManager ModuleManager { get; set; }

    protected IRegionManager RegionManager { get; set; }

    protected BaseCommand(IRegionManager regionManager, IModuleManager moduleManager, string pageName = null)
    {
        RegionManager = regionManager;
        ModuleManager = moduleManager;
        Text = GetButtonText(pageName + "_BtnTxt");
        Image = (ImageSource)Application.Current.FindResource(pageName + "_BtnImg");
    }

    private string _text;

    private ImageSource _image;

    public ICommand CommandToExecute => new DelegateCommand<object>(Command, Evaluate);

    protected abstract void Command(object obj);

    protected virtual bool Evaluate(object obj)
    {
        return false;
    }

    public string Text
    {
        get { return _text; }
        set { SetProperty(ref _text, value); }
    }

    public ImageSource Image
    {
        get { return _image; }
        set { SetProperty(ref _image, value); }
    }

    protected string GetButtonText(string key)
    {
        string uiString;
        var locExtension = new LocTextExtension
        {
            Key = "Resources",
            ResourceIdentifierKey = key
        };
        locExtension.ResolveLocalizedValue(out uiString);
        return uiString;
    }
}

and then the command specific stuff in the viewmodel.

public class Page1CommandViewModel : BaseCommand, IPage1CommandViewModel
{
    public Page1CommandViewModel(IRegionManager regionManager, IModuleManager moduleManager) : base( regionManager, moduleManager, PageNames.Page1 )
    {
    }

    protected override void Command(object obj)
    {
        Task.Run(() =>
        {
            ModuleManager.LoadModule(ModuleNames.Page1Module);
            RegionManager.RequestNavigate(RegionNames.ContentRegion, new Uri(PageNames.Page1, UriKind.Relative));
        });
    }
}

If anyone could point me in the right direction it'd be greatly appreciated.

user3265613
  • 355
  • 2
  • 14
  • Tooltip on click is weird. Why not just wrap the button in some panel which will display the tooltip? This way it will be visibile even if button itself is disabled. – icebat Dec 12 '16 at 15:58
  • The application will be running on a touchscreen, which is why the onclick is needed rather than on hover. – user3265613 Dec 12 '16 at 16:00
  • It's not really on 'click' then, is it? Tooltip is not a convenient solution in touch UI. If you really need to show the info this way, why not drop disabling the button altogether and just show some message when user clicks on it depending on some conditions? – icebat Dec 12 '16 at 16:08
  • Depends on which touch screens we get. The resistive ones we've been working with in the past (and probably the future) don't translate finger presses to touch events, but to click events. Or at least that's how it seems. I think they only register as touch events on the capacitive screens (i may be wrong) – user3265613 Dec 12 '16 at 16:18

2 Answers2

0

Maybe instead of disabling the button, re-point the button to a different method, which would then display your error/tooltip message. (You could then pass in the string stating the reason for the inactivity in your method paramaters/variables.)

I would also advise you change the class/visual properties of the button so that it looks disabled.

Del
  • 416
  • 2
  • 13
  • Yeah I had thought of that as a potential way of resolving the problem. Was just hoping there was some way of working this without smoke and mirrors, but it is currently my fallback plan (coworker already has a working prototype that works in the same way.) – user3265613 Dec 12 '16 at 16:28
  • Yeah, there is a whole debate on the place/viability of tooltips. Does seem weird there doesnt seem to be a standard, or even a shared opinion of there being a legitimate need for them. http://stackoverflow.com/questions/1737773/tooltips-in-the-era-of-touch – Del Dec 12 '16 at 16:32
  • Well, your answer did help lead me to something which has kinda worked. I've now wrapped the button in a content control, and have the tooltip assigned to the contentcontrol instead. This way button can get disabled, but content control can still handle the events for me. – user3265613 Dec 12 '16 at 16:41
  • Also taking a look at that post you linked, they're missing out one big section where touchscreen and tooltips are both quite often required. Manufacturing (what this app is for). Hardware is out of position, something not set up correctly, many variables which affect which controls are displayed means tooltips are pretty much a necessity. – user3265613 Dec 12 '16 at 16:43
0

After much googling, I've come up with a solution myself, thanks in part to comments others had made leading me in the right direction. Wrapped up my button in a contentControl, and instead have applied the tooltip to this.

<ContentControl MouseDown="ContentControl_MouseDown">
    <ContentControl.ToolTip>
        <ToolTip Placement="Mouse" Content="Testing" />
    </ContentControl.ToolTip>
    <Button Focusable="True" x:Name="Btn1" Command="{Binding CommandToExecute}" Tag="{Binding Text}" Foreground="{x:Null}" Style="{DynamicResource ButtonStyle}" ToolTipService.ShowOnDisabled="true">
        <shellModule:AutoGreyableImage  Source="{Binding Image}" />
    </Button>
</ContentControl>

And on the button.xaml.cs put in events to handle timings of the button click etc.

    Timer Timer { get; set; }
    ToolTip toolTip { get; set; }

    public CommandButton()
    {
        InitializeComponent();
        Timer = new Timer {Interval = 3000};
        Timer.Elapsed += OnTimerElapsed;
    }

    private void CloseToolTip()
    {
        if (toolTip != null)
        {
            toolTip.IsOpen = false;
        }
    }

    private void OnTimerElapsed(object sender, ElapsedEventArgs e)
    {
        Timer.Stop();
        Application.Current.Dispatcher.BeginInvoke((Action)CloseToolTip, DispatcherPriority.Send);
    }

    private void ContentControl_MouseDown(object sender, MouseButtonEventArgs e)
    {
        toolTip = ((ToolTip)((Control)sender).ToolTip);
        toolTip.IsOpen = true;
        Timer.Start();
    }

timers taken from the following location.

https://social.msdn.microsoft.com/Forums/vstudio/en-US/9e3eb4ab-ed0f-40ad-ad47-a1fff8e0fe8d/tooltips-in-wpf-touch-applications?forum=wpf

This allows the button to be disabled, and the tooltip to still display on click. All I need to do now is wrap up the tooltip contents in a binding and disable the tooltip on hover (not required) and it's all solved.

Leaving question open for the time being however, as a better solution may present itself.

user3265613
  • 355
  • 2
  • 14
  • Well as it turns out this isn't an ideal solution either. Cannot get the tooltip to work with binding. No text is getting through to it, may need to look into this a bit more. – user3265613 Dec 13 '16 at 15:17
  • Ah, setting the tooltip = {Binding blah} directly on the ContentControl works fine, it's only if I try binding it when it's inside the ContentControl.Tooltip tags it fails. Still no idea what the difference there is, but this works for my purposes. – user3265613 Dec 14 '16 at 15:39