sgonchar
Topic Author
Posts: 48
Joined: 15 Mar 2021, 22:11

how to trigger xaml button from cpp

31 Mar 2021, 17:51

Hello,
New to noesis and xaml, forgive a possibly noob question.

We have a need to trigger a button from cpp.
There are likely several ways to do it. Currently, done via FindName("somebutton").CommandParameter() and running that command param through the Command that it would have trigged via mouse click.
This is not optimal as it assumes a lot about structure of the xaml. We would really like this to be very disjointed.

Exact use case: a key needs to activate on an screen button, button will not be in focus/selected, button changes depending on what screen/page is visible at the time. ala: several xaml screens/panels need, say, space-bar to "press" a button defined whos behavior should be defined only in xaml.

1) side question: given Noesis::BaseButton, how does one active the click() on it? Fetching CommandParameter and manually running it seems too manual. Can one "activate" the button and let to do what it's supposed to do? (in case it does more then just running commands, recreating entire trigger block seems overkill).

2) main question: a better solution would be to trigger the button via a binding/event. This is to avoid using FindName(""). We'd like this because we want the xaml button to be ultimately responsible for defining the behavior. This button may not be in focus or even focusable. This button may move inside/out of other blocks and may not even exist on some screens/panels/pages.
2a) is there a good example of this in the samples? If not, how does one trigger a button click via event or binding from cpp with no direct reference to BaseButton?
2b) given a binding trigger/activator is possible, is there a way for xaml button to test if it itself is visible and it's parents parents are visible before self activating?

Thank you.
 
sgonchar
Topic Author
Posts: 48
Joined: 15 Mar 2021, 22:11

Re: how to trigger xaml button from cpp

31 Mar 2021, 18:05

Here's an example of how best case might work:
<Button
      Name="GenericSpaceTriggerButton"  Style="{StaticResource MenuButtonStyle}"  
      Command="{Binding Navigate}"   CommandParameter="SpaceDoStuff"
      Focusable="False"
      Text="Press Space To Do Stuff"
    >
    <i:Interaction.Triggers> 
        <SomeKindOfTrigger EventOrBindingName="ActivateSpaceDoStuff">
            <i:Invoke self activate if visible and parents visible />
        </SomeKindOfTrigger>
    </i:Interaction.Triggers>
</Button>
Then in CPP something along the lines of (if one even has to go through mainwindow):
  mApplication->GetMainWindow()->SomeKindOfTrigger("ActivateSpaceDoStuff");
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: how to trigger xaml button from cpp

31 Mar 2021, 20:29

If you want to trigger a command in response of a Key press you can use a KeyTrigger and InvokeCommandAction.
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
  <i:Interaction.Triggers>
    <ei:KeyTrigger FiredOn="KeyDown" Key="Space">
      <i:InvokeCommandAction Command="{Binding Navigate}"  CommandParameter="SpaceDoStuff"/>
    </ei:KeyTrigger>
  <i:Interaction.Triggers>
  ...
</UserControl>
If what you need is to trigger from the view model an event that you can listen in XAML, then you should use the DataEventTrigger:
<UserControl
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
   xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
   xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions">
  <i:Interaction.Triggers>
    <noesis:DataEventTrigger Source="{Binding}" EventName="ActivateSpaceDoStuff">
      <i:InvokeCommandAction Command="{Binding Navigate}"  CommandParameter="SpaceDoStuff"/>
    </noesis:DataEventTrigger>
  </i:Interaction.Triggers>
  ...
</UserControl>
Is any of this useful in your case?
 
sgonchar
Topic Author
Posts: 48
Joined: 15 Mar 2021, 22:11

Re: how to trigger xaml button from cpp

31 Mar 2021, 20:57

Hello,
Thank you for the ideas!
<ei:KeyTrigger FiredOn="KeyDown" Key="Space">
This does trigger without focus! For some reason I really being in focus is required for getting keyboard events. Two more questions about it:
1a) I can't seem to find GamepadContext2 in options for the key, it's not part of keys?
1b) it seems to trigger all instances of this button, how does one check for self and parent visibility? (or does self inherit parents' visibility?)

For:
<noesis:DataEventTrigger Source="{Binding}" EventName="ActivateSpaceDoStuff">
This looks great!
2a) In the DataEventTrigger page has examples to go xaml -> cpp and event is handled in cpp. I'm wondering if there's an example of cpp generating an event, then sending it to xaml ?
2b) if there is a way for cpp to generate an event and sent it xaml, as 1b, this might be triggered for all listeners, I'm wondering if/how I can limit the send even to a specific UserControl/BaseComponent or check for self and parent visibilities again?
 
sgonchar
Topic Author
Posts: 48
Joined: 15 Mar 2021, 22:11

Re: how to trigger xaml button from cpp

31 Mar 2021, 22:59

Ok, so while exploring stuff for 1a/1b found these:
https://www.noesisengine.com/docs/App.I ... igger.html now this totally works via gamepad.

Here's what I have so far, it checks self visibility and and entire stack (or supposed to)
          <noesis:GamepadTrigger FiredOn="ButtonDown" Button="Context2">
          <i:InvokeCommandAction Command="{Binding Navigate}"  CommandParameter=""/>
          <i:Interaction.Behaviors>
            <ei:ConditionBehavior>
              <ei:ConditionalExpression>
                <ei:ComparisonCondition LeftOperand="{Binding Path=IsVisible, ElementName=SpaceDoStuff}" Operator="Equal" RightOperand="True"/>
              </ei:ConditionalExpression>
            </ei:ConditionBehavior>
          </i:Interaction.Behaviors>
        </noesis:GamepadTrigger>
This should work ... but nothing triggers.
***EDIT: triggers all fine, this method works great! (I have continues controller issues , like it doesn't register sometimes)
***EDIT 2: turns out doesn't work that great, if an input field is currently highlighted (say input player name), all the events go to that field. Is there a way to make these focus/highlight agnostic?

I'm still very interested to do to 2, ala "ActivateSpaceDoStuff" as it's probably the best solution for us
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: how to trigger xaml button from cpp

01 Apr 2021, 10:47

As you found, we created GamepadTrigger to expose gamepad buttons. Both KeyTrigger and GamepadTrigger hook by default to the root of the tree to listen to any KeyDown that wasn't handle by any other control. You can add these trigger on a specific control and set the ActiveOnFocus="True" but then the control needs to be focused to trigger, so I guess that won't work for you. You can create your own trigger by inheriting from interactivity TriggerBase/EventTriggerBase and register to PreviewKeyDown to get all the keys before they can be handled, please let me know if you need help to explore this option.

Anyway using DataEventTrigger seems the best option here as you said.
I'm wondering if there's an example of cpp generating an event, then sending it to xaml ?
That is exactly what DataEventTrigger is designed for. Your view model (the one bound to the control) exposes in its reflection an event that can be invoked whenever the ViewModel wants (C++ -> XAML).
struct ViewModel: public BaseComponent
{
  ...
  void OnDownloadFinished()
  {
    _downloadFinished(this, EventArgs::Empty);
  }
  EventHandler _downloadFinished;

  NS_IMPLEMENT_INLINE_REFLECTION(ViewModel, BaseComponent)
  {
    NsEvent("DownloadFinished", &ViewModel::_downloadFinished);
  }
};
Then in xaml, the DataEventTrigger listens to that event, and performs the actions you need: fire animations, go to a different state, change some property values, even invoke a command (XAML -> C++).
<Grid
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
   xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
   xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions">
  <TextBlock Text="Download Finished!" Visibility="Collapsed">
    <i:Interaction.Triggers>
      <noesis:DataEventTrigger Source="{Binding}" EventName="DownloadFinished">
        <ei:ChangePropertyAction PropertyName="Visibility" Value="Visible"/>
      </noesis:DataEventTrigger>
    </i:Interaction.Triggers>
  </TextBlock>
</Grid>
 
sgonchar
Topic Author
Posts: 48
Joined: 15 Mar 2021, 22:11

Re: how to trigger xaml button from cpp

01 Apr 2021, 16:49

invoked whenever the ViewModel wants (C++ -> XAML).
My mistake, for some reason I read it as xaml to cpp only, Thank you! This also now works.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: how to trigger xaml button from cpp

01 Apr 2021, 17:57

Don't worry, glad to hear it works!

Who is online

Users browsing this forum: No registered users and 30 guests