esses
Topic Author
Posts: 9
Joined: 26 Sep 2016, 16:13

Using EventTriggers gives error

19 Oct 2016, 14:54

Hi,

we are in need to get MouseEnter and MouseExit from buttons or their images with id parameter. These buttons live in an ItemsControl.

I have tried using System.Windows.Interactivity namespace to use Triggers, but with little luck. If I use Trigger it gives me this error:

NoesisException: Resource Assets/GloryAssets/Cok_Xaml/Editors/UserControls/ArenaEditorWindow.xaml not found
Noesis.Error.Check () (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisError.cs:26)
Noesis.UIRenderer.Noesis_CreateRenderer (IntPtr root) (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisUIRendererImports.cs:90)
Noesis.UIRenderer..ctor (Noesis.FrameworkElement content, Vector2 offscreenSize, UnityEngine.GameObject target) (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisUIRenderer.cs:117)
NoesisGUIPanel.LoadXaml () (at Assets/Plugins/NoesisGUI/Scripts/NoesisGUIPanel.cs:529)
NoesisGUIPanel.OnEnable () (at Assets/Plugins/NoesisGUI/Scripts/NoesisGUIPanel.cs:400)


Namespace:
<UserControl x:Class="Assets.GloryAssets.Scripts.GUI.UserControls.ArenaEditorWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:Assets.GloryAssets.Scripts.GUI.UserControls"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"            
             mc:Ignorable="d" 
             d:DesignHeight="1080" d:DesignWidth="1920"
             x:Name="root">
Sample button:
       <Button Content="Button" Width="300" Height="50">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseEnter">
                            <i:InvokeCommandAction Command="{Binding PropItemMouseEnterCommand}" 
                                CommandParameter="1" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Using EventTriggers gives error

19 Oct 2016, 19:18

Hi,

Interactivity namespace is defined by a Blend SDK extension assembly and we don't implement it.
Anyway we implement the standard WPF EventTriggers that can be used in FrameworkElement.Triggers and inside ControlTemplate.Triggers collections.
<Grid.Triggers>
  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
    <BeginStoryboard Storyboard="{StaticResource onLoadedAnim}"/>
  </EventTrigger>
</Grid.Triggers>
<ControlTemplate.Triggers>
  <EventTrigger RoutedEvent="UIElement.MouseEnter">
    <BeginStoryboard Storyboard="{StaticResource onMouseEnterAnim}"/>
  </EventTrigger>
</ControlTemplate.Triggers>
Have you tried that?

The error message seems to point to a syntax error during xaml parsing, so xaml resource is not correctly generated. When a xaml is processed we dump warning and error messages to Unity Console, and we also show in NoesisGUIPanel if the attached xaml has errors, as explained in our tutorial: http://www.noesisengine.com/docs/Gui.Co ... -noesisgui

Regards.
 
esses
Topic Author
Posts: 9
Joined: 26 Sep 2016, 16:13

Re: Using EventTriggers gives error

20 Oct 2016, 10:50

Hey,

is it possible to use commands with the WPF EventTriggers?
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Using EventTriggers gives error

20 Oct 2016, 19:27

No, it is not possible to invoke a Command directly from the EventTrigger.
But it can be done using animation and a custom class that stores and invokes the command, something like this:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Rectangle x:Name="rect" Width="200" Height="100" Fill="Red">
        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="UIElement.MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames
                            Storyboard.TargetName="enterCommandInvoker"
                            Storyboard.TargetProperty="Invoke">
                            <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                            <DiscreteBooleanKeyFrame KeyTime="0:0:0.01" Value="False"/>
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
    <InvokeCommand x:Name="enterCommandInvoker" Command="{Binding EnterCommand}"
        CommandParameter="{Binding ElementName=rect}"/>
</Grid>
public class InvokeCommand: FrameworkElement
{
    public static DependencyProperty CommandProperty = DependencyProperty.Register(
        "Command", typeof(ICommand), typeof(InvokeCommand), new PropertyMetadata(null));

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static DependencyProperty CommandParameterProperty = DependencyProperty.Register(
        "CommandParameter", typeof(object), typeof(InvokeCommand), new PropertyMetadata(null));

    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }

    public static DependencyProperty InvokeProperty = DependencyProperty.Register(
        "Invoke", typeof(bool), typeof(InvokeCommand),
        new PropertyMetadata(false, OnInvokeChanged));

    public bool Invoke
    {
        get { return (bool)GetValue(InvokeProperty); }
        set { SetValue(InvokeProperty, value); }
    }

    private static void OnInvokeChanged(DependencyObject sender,
        DependencyPropertyChangedEventArgs e)
    {
        bool invoke = (bool)e.NewValue;
        if (invoke)
        {
            InvokeCommand invoker = (InvokeCommand)sender;
            invoker.Command.Execute(invoker.CommandParameter);
        }
    }
}
 
esses
Topic Author
Posts: 9
Joined: 26 Sep 2016, 16:13

Re: Using EventTriggers gives error

25 Oct 2016, 13:35

Hey, thanks for the reply. I can successfully use the rectangle and trigger the MouseEnter event. However, in Blend I can't use this part:
 <InvokeCommand x:Name="enterCommandInvoker" Command="{Binding EnterCommand}"
        CommandParameter="{Binding ElementName=rect}"/>
"The type InvokeCommand was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built."

I have included InvokeCommand.cs in the Blend project and built the project but with no help.
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Using EventTriggers gives error

25 Oct 2016, 18:41

I think you would need to use a xaml namespace.

In which namespace is InvokeCommand class defined in Blend?
For example, if you have the class defined like this:
namespace Esses
{
  public class InvokeCommand: FrameworkElement { ... }
}
You have to add the following in your xaml:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:Esses">
    ...
    <local:InvokeCommand .../>
    ...
</Grid>
 
esses
Topic Author
Posts: 9
Joined: 26 Sep 2016, 16:13

Re: Using EventTriggers gives error

31 Oct 2016, 16:14

Hey, thanks for the reply. Now it's defined in Blend. For some reason the command doesn't fire though.

I put the InvokeCommand.cs in Assets.GloryAssets.Scripts.GUI.NoesisCommands namespace:
 xmlns:commandou="clr-namespace:Assets.GloryAssets.Scripts.GUI.NoesisCommands" 
namespace Assets.GloryAssets.Scripts.GUI.NoesisCommands
{
    public class InvokeCommand : FrameworkElement
    {
        public static DependencyProperty CommandProperty = DependencyProperty.Register(
            "Command", typeof(ICommand), typeof(InvokeCommand), new PropertyMetadata(null));

        public ICommand Command


ArenaEditorWindow.xaml.cs:
public DelegateCommand EnterCommand { get; private set; }
  public ArenaEditorWindow()
        {
[..]
            EnterCommand = new DelegateCommand(Enter);

    
            this.Initialized += OnInitialized;

#if UNITY
            InitializeComponent();

            [..] 

If I remove the line
 <commandou:InvokeCommand x:Name="enterCommandInvoker" Command="{Binding EnterCommand}"
        CommandParameter="{Binding ElementName=rect}"/>
on mouse enter I get the following error:

NoesisException: The target name 'enterCommandInvoker' cannot be found in the xaml namescope
Noesis.Error.Check () (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisError.cs:26)

...which indicates that the mouse enter works, but for some reason the command doesn't fire at all.
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Using EventTriggers gives error

31 Oct 2016, 17:15

I made a simple example to show you how can be done, it is working fine for me.

InvokeCommandTestBehavior.cs
using UnityEngine;
using System.Windows.Input;
using Noesis;


namespace Assets.InvokeCommandTest
{
    public class InvokeCommand : FrameworkElement
    {
        public static DependencyProperty CommandProperty = DependencyProperty.Register(
            "Command", typeof(ICommand), typeof(InvokeCommand), new PropertyMetadata(null));

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public static DependencyProperty CommandParameterProperty = DependencyProperty.Register(
            "CommandParameter", typeof(object), typeof(InvokeCommand), new PropertyMetadata(null));

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public static DependencyProperty InvokeProperty = DependencyProperty.Register(
            "Invoke", typeof(bool), typeof(InvokeCommand),
            new PropertyMetadata(false, OnInvokeChanged));

        public bool Invoke
        {
            get { return (bool)GetValue(InvokeProperty); }
            set { SetValue(InvokeProperty, value); }
        }

        private static void OnInvokeChanged(DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
        {
            bool invoke = (bool)e.NewValue;
            if (invoke)
            {
                InvokeCommand invoker = (InvokeCommand)sender;
                invoker.Command.Execute(invoker.CommandParameter);
            }
        }
    }

    public class Context
    {
        public ICommand EnterCommand { get; private set; }

        public Context()
        {
            EnterCommand = new Noesis.Samples.DelegateCommand(OnEnter);
        }

        private void OnEnter(object param)
        {
            FrameworkElement element = (FrameworkElement)param;
            Debug.Log("OnMouseEnter: " + (element != null ? element.Name : "?"));
        }
    }
}


public class InvokeCommandTestBehavior : MonoBehaviour
{
    void Start()
    {
        var gui = GetComponent<NoesisGUIPanel>();
        var content = gui.GetContent();
        content.DataContext = new Assets.InvokeCommandTest.Context();
    }
} 
InvokeCommandTest.xaml
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:Assets.InvokeCommandTest">
    <Rectangle x:Name="rect" Width="200" Height="100" Fill="Red">
        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="UIElement.MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames
                            Storyboard.TargetName="enterCommandInvoker"
                            Storyboard.TargetProperty="Invoke">
                            <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                            <DiscreteBooleanKeyFrame KeyTime="0:0:0.01" Value="False"/>
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
    <local:InvokeCommand x:Name="enterCommandInvoker"
        Command="{Binding EnterCommand}"
        CommandParameter="{Binding ElementName=rect}"/>
</Grid> 
I added a NoesisGUIPanel component to the Main Camera object, then drag and drop InvokeCommandTest.xaml to its Xaml property, and finally added too InvokeCommandTestBehavior script to Main Camera.
After clicking play, a message is written to the Console every time mouse enters the red rectangle.

Please let me know if you don't understand anything from the example, or if you can't make it work.
 
esses
Topic Author
Posts: 9
Joined: 26 Sep 2016, 16:13

Re: Using EventTriggers gives error

02 Nov 2016, 10:02

Hey, it worked for a while. I had placed the files not in Assets/InvokeCommandTest folder and wondered if it would work after moving them to that folder. For some reason it started working after moving. Then I tried to confirm this by moving them away from that folder, and it still worked (?). But now it stopped working. I don't even get the error anymore when hovering, but the red square is drawn correctly.
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Using EventTriggers gives error

02 Nov 2016, 12:30

The folder where you place the files shouldn't matter, because the namespace could be whatever you want.
What you have to make sure is that the xaml is correctly processed (without errors) after the InvokeCommand class is compiled and available in the assembly.

Try to rebuild xaml resources to see if there is some synchronization problems between data and code. You can do that in Tools > NoesisGUI > Settings... panel from Unity's top menu, by pressing the 'Rebuild' button.

Who is online

Users browsing this forum: Google [Bot] and 1 guest