Windows 8.1: Behaviors on Flyouts don't Work

1.5k views Asked by At

I am developing a windows 8.1 app using VS 2013 and MVVM Light.

The following code shows the behavior in a flyout within an appbar:

<AppBarButton.Flyout>
    <Flyout x:Name="FlyoutCalculator"
            Placement="Top"
            FlyoutPresenterStyle="{StaticResource FlyoutPresenterBaseStyle}">

        <uc:Calculator ApplyCommand="{Binding CancelCommand}"
                       CancelCommand="{Binding CancelCommand}"                                           
                       Available="{Binding AvailableCounter, Mode=OneWay}"
                       SelectedItem="{Binding SelectedItem, Mode=TwoWay}"/>
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Opening">
                <core:InvokeCommandAction Command="{Binding ShowCurrentCostsCommand}" />
            </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </Flyout>
</AppBarButton.Flyout>

Unfortunately I get an exception while compiling the app:

WinRT-Informationen: Cannot add instance of type Microsoft.Xaml.Interactions.Core.EventTriggerBehavior to a collection of type Microsoft.Xaml.Interactivity.BehaviorCollection

Other Behaviors in the View do work, does someone know a solution to this?

2

There are 2 answers

0
Sebastian On

I do not have a solution but: I'm not using Flyouts in my Windows 8.1 App, I'm using a UserControl on which I have added a EventTriggerBehavior as you did. And I get exactly the same Errormessage from VisualStudio at runtime. As I am using a RoutedEventHandler this could cause the Problem as you use

EventHandler<object> Opening

as the Trigger for the Behavior. But that is just an idea of what is the problem.

For me I have found an answer:

I have changed the Type of my RoutedEventHandler to be just a normal EventHandler. And the Method inside the CodeBehind which triggers the RoutedEventHandler is invoked with only the sender, because I dont know how to convert RoutedEventArgs into EventArgs, but as long as I dont need the EventArgs it's not a problem.

You could also make a workaround by creating a UserControl with a Flyout Control and make the Opening Event public to the Page where you use it. Then you can add the EventTriggerBehavior to the UserControl and connect it to your custom Opening Event and you should get the expected behavior.

0
Paul Abbott On

Extremely late answer here, but I had the same issue and came up with a solution after finding this post.

I just created a custom behavior specifically for flyouts, used like this. OpenActions will execute when the flyout is opened, and CloseActions will execute when the flyout closes. In this case, I wanted the bottom app bar to not be visible when the flyout was open.

<Flyout Placement="Full">
  <i:Interaction.Behaviors>
    <behaviors:FlyoutBehavior>
      <behaviors:FlyoutBehavior.OpenActions>
        <core:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" TargetObject="{Binding ElementName=CommandBar}" />
      </behaviors:FlyoutBehavior.OpenActions>
      <behaviors:FlyoutBehavior.CloseActions>
        <core:ChangePropertyAction PropertyName="Visibility" Value="Visible" TargetObject="{Binding ElementName=CommandBar}" />
      </behaviors:FlyoutBehavior.CloseActions>
    </behaviors:FlyoutBehavior>
  </i:Interaction.Behaviors>
  <Grid>
    ...
  </Grid>
</Flyout>

Code is here:

class FlyoutBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject { get; private set; }

    public void Attach(Windows.UI.Xaml.DependencyObject associatedObject)
    {
        var flyout = associatedObject as FlyoutBase;

        if (flyout == null)
            throw new ArgumentException("FlyoutBehavior can be attached only to FlyoutBase");

        AssociatedObject = associatedObject;

        flyout.Opened += FlyoutOpened;
        flyout.Closed += FlyoutClosed;
    }

    public void Detach()
    {
        var flyout = AssociatedObject as FlyoutBase;

        if (flyout != null)
        {
            flyout.Opened -= FlyoutOpened;
            flyout.Closed -= FlyoutClosed;
        }
    }

    public static readonly DependencyProperty OpenActionsProperty =
        DependencyProperty.Register("OpenActions", typeof(ActionCollection), typeof(FlyoutBehavior), new PropertyMetadata(null));

    public ActionCollection OpenActions
    {
        get { return GetValue(OpenActionsProperty) as ActionCollection; }
        set { SetValue(OpenActionsProperty, value); }
    }

    public static readonly DependencyProperty CloseActionsProperty =
        DependencyProperty.Register("CloseActions", typeof(ActionCollection), typeof(FlyoutBehavior), new PropertyMetadata(null));

    public ActionCollection CloseActions
    {
        get { return GetValue(CloseActionsProperty) as ActionCollection; }
        set { SetValue(CloseActionsProperty, value); }
    }

    private void FlyoutOpened(object sender, object e)
    {
        foreach (IAction action in OpenActions)
        {
            action.Execute(AssociatedObject, null);
        }
    }

    private void FlyoutClosed(object sender, object e)
    {
        foreach (IAction action in CloseActions)
        {
            action.Execute(AssociatedObject, null);
        }
    }

    public FlyoutBehavior()
    {
        OpenActions = new ActionCollection();
        CloseActions = new ActionCollection();
    }
}