Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flyout Animation Problem MahApps #1655

Closed
ferrann opened this issue Nov 19, 2014 · 11 comments
Closed

Flyout Animation Problem MahApps #1655

ferrann opened this issue Nov 19, 2014 · 11 comments

Comments

@ferrann
Copy link

ferrann commented Nov 19, 2014

Hi guys, Im trying to create your Flyouts with dynamic content and I have a little issue when the Flyout is executed for the first time. When I press a button that shows the Flyout I mentioned before, the flyout appears without the slide-fade default animation.

However, If I close the Flyout or I try to open the same Flyout again the animations works perfectly. I wasted many time trying to fix this, but I dont know whats going wrong and moreover I tryied to create a new project simulating the same process and it works perfectly .

I have an empty MainWindow that his content is an User Control "Menu" with some buttons. When I press one of the buttons the "Menu" shows a Flyout that have content from another User Control.

My MainWindow.xaml:

<Controls:MetroWindow.Resources>
            <DataTemplate DataType="{x:Type viewModels:MenuViewModel}">
                  <views:Menu />
           </DataTemplate>

           <DataTemplate DataType="{x:Type viewModels:EmpleadoDetailViewModel}">
                  <views:EmpleadoDetailView />
           </DataTemplate>
</Controls:MetroWindow.Resources>

<!-- Dynamic Flyout Content -->
    <Controls:MetroWindow.Flyouts>
        <Controls:FlyoutsControl>
            <Controls:Flyout Header="{Binding FlyoutHeader}"
                             Width="600"
                             Position="Right"
                             IsModal="True">
                <ContentControl Content="{Binding ContenidoFlyoutUC}" />
            </Controls:Flyout>
        </Controls:FlyoutsControl>
    </Controls:MetroWindow.Flyouts>

    <StackPanel>
        <ContentControl Name="ContentControl" Content="{Binding ActualUC}"/>
    </StackPanel>

MainWindow constructor:

public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel(this);
        }

In my MainWindowViewModel I also have:

public MainWindow _mainW; 
public ICommand MenuCommand { get; private set; }

public MainWindowViewModel (MainWindow mainW){
        this._mainW = mainW;
        MenuCommand = new RelayCommand(OpenMenu);
}

private void OpenMenu (){
       this.ActualUC =  new MenuViewModel(this);
}

private ViewModelBase _ActualUC;

        public ViewModelBase ActualUC
        {
            get { return _ActualUC; }

            set
            {
                if (_ActualUC == value)
                {
                    return;
                }

                _ActualUC = value;
                NotifyPropertyChanged("ActualUC");
            }
        }

public ViewModelBase _ContenidoFlyoutUC;

        public ViewModelBase ContenidoFlyoutUC
        {
            get { return _ContenidoFlyoutUC; }

            set
            {
                if (_ContenidoFlyoutUC == value)
                {
                    return;
                }

                _ContenidoFlyoutUC = value;
                NotifyPropertyChanged("ContenidoFlyoutUC");
            }
        }

 public void OpenCloseFlyout(int n)    
        {
            var flyout = this._mainW.Flyouts.Items[n] as Flyout;
            if (flyout == null)
            {
                return;
            }

            flyout.IsOpen = !flyout.IsOpen;
        }

And Finally I have a MenuWindow that contains a Button with a Command attached to a function that calls the MainWindowViewModel OpenCloseFlyout(0) function:

private MainViewModel _mainVM;
public ICommand OpenFlyoutCommand{ get; private set; }

 public MenuViewModel (MainViewModel mainVM)
      {
          _mainVM = mainVM;
          OpenFlyoutCommand = new RelayCommand(OpenFlyout);
      }

 private void OpenFlyout(){
          _mainVM.ContenidoFlyoutUC = new EmpleadoDetailViewModel(_mainVM);
          _mainVM.OpenCloseFlyout(0);
      }
@punker76
Copy link
Member

@ferrann which version? if you use 0.14 try using the latest alpha and chekc again. thx

@ferrann
Copy link
Author

ferrann commented Nov 19, 2014

I dont know what is alpha. It seems something like the newest versions right?
Im using 0.14.0.0, how can I get the latest alpha?

Thank you @punker76

@ghost
Copy link

ghost commented Nov 19, 2014

Hi @ferrann

Go to Manage NuGet Packages By right clicking References --> Click updates

There will be drop down with stable only and Include Pre-Releases --> Select Include Pre-Releases

When Pre-Release Pops up --- Click Update 👍

@thoemmi
Copy link
Collaborator

thoemmi commented Nov 19, 2014

I've experienced the same issue. The animation runs only if IsOpen changes after the visual is created. The trick is to defer the opening like this:

view.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, (Action)(() => flyout.IsOpen = true));

@ferrann
Copy link
Author

ferrann commented Nov 20, 2014

Finally the solution of that issue was that @thoemmi said. Im going to attach that solution adapted to my code for if someone wants to test it:

public void OpenCloseFlyout(int n)
{
var flyout = this._mainW.Flyouts.Items[n] as Flyout;
if (flyout == null)
{
return;
}
_mainW.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, (Action)(() => flyout.IsOpen = !flyout.IsOpen));
//flyout.IsOpen = !flyout.IsOpen;
}

Thank you guys, thats an excellent community.

@punker76
Copy link
Member

@thoemmi
Copy link
Collaborator

thoemmi commented Nov 21, 2014

@punker76 See https://github.com/MahApps/MahApps.Metro/blob/master/samples/MetroDemo/ExampleWindows/FlyoutDemo.xaml.cs#L132-133, which I added in 1a88a84 . Replace these two lines with flyout.IsOpen = true, and you'll see that the flyout appears immediately without any animation.

@punker76
Copy link
Member

@thoemmi my mistake

@thoemmi
Copy link
Collaborator

thoemmi commented Nov 21, 2014

@punker76
Copy link
Member

@thoemmi ok, maybe we can do the Dispatcher stuff always at the property changed event

private static void IsOpenedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
    var flyout = (Flyout)dependencyObject;

    Action a = () => {
        if (e.NewValue != e.OldValue)
        {
            if ((bool)e.NewValue)
            {
                if (flyout.hideStoryboard != null)
                {
                    // don't let the storyboard end it's completed event
                    // otherwise it could be hidden on start
                    flyout.hideStoryboard.Completed -= flyout.HideStoryboard_Completed;
                }
                flyout.Visibility = Visibility.Visible;
                flyout.ApplyAnimation(flyout.Position, flyout.AnimateOpacity);
            }
            else
            {
                if (flyout.hideStoryboard != null)
                {
                    flyout.hideStoryboard.Completed += flyout.HideStoryboard_Completed;
                }
                else
                {
                    flyout.Hide();
                }
            }

            VisualStateManager.GoToState(flyout, (bool)e.NewValue == false ? "Hide" : "Show", true);
        }

        flyout.RaiseEvent(new RoutedEventArgs(IsOpenChangedEvent));
    };

    flyout.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, a);
}

i found no issue with this /cc @flagbug

@thoemmi
Copy link
Collaborator

thoemmi commented Nov 21, 2014

Maybe DispatcherPriority.Background is a better fit, see MSDN for explanation of this enum. Anything lower than DispatcherPriority.DataBind should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants