I want to create a side menu for a specific listboxitem or longlistselector's item
like the picture
when your press and hold the listboxitem the blue panel comes out, is there anyway to this ?
I managed the Hold event on the item, but not the side menu !
There are a few possible ways to do this, but the basic idea is that you add the menu in a hidden or collapsed state, and then trigger an animation on the Hold event. Here is a simple example (using the interactivity DLLs System.Windows.Interactivity and Microsoft.Expression.Interactions.Core):
<Grid xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
<Grid.Resources>
<Storyboard x:Name="ShowMenu">
<DoubleAnimation Storyboard.TargetName="translate" Storyboard.TargetProperty="X"
To="0" Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Name="HideMenu">
<DoubleAnimation Storyboard.TargetName="translate" Storyboard.TargetProperty="X"
To="-300" Duration="0:0:0.3" />
</Storyboard>
</Grid.Resources>
<Grid Width="300" Background="LightBlue">
<Grid.RenderTransform>
<TranslateTransform x:Name="translate" X="-300" />
</Grid.RenderTransform>
<!-- Menu popup content here -->
<TextBlock Text="Menu">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Hold">
<ei:ControlStoryboardAction Storyboard="{StaticResource HideMenu}" ControlStoryboardOption="Play" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</Grid>
<Grid>
<!-- Item content here -->
<TextBlock Text="Item">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Hold">
<ei:ControlStoryboardAction Storyboard="{StaticResource ShowMenu}" ControlStoryboardOption="Play" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock
</Grid>
</Grid>
You can include this menu in your Item Template and set its Visibility to Collapsed. And then add code to your Hold event that will show it. Take a look at Storyboard class for possible animations.
Related
I am using Material Design in XAML and I'm trying to create a navigation drawer. I want the drawer to slide in and out on opening/closing button click. For this purpose I've created two buttons for opening and closing, keeping one of them invisible. On top of that I have animations declared in window's resources which are used in EventTriggers section.
But apart from starting animations, I also have to hide the clicked button and show the another one.
For now I've created an event handler for both buttons and I'm keeping the code for managing visibility in code-behind as it seemed to be the easiest solution. However I'm afraid it is breaking the MVVM pattern, but on the other hand, I shouldn't bind this event to a command in a view model because the code is messing with UI-related things.
Animations and Window Triggers:
<Window.Resources>
<Storyboard x:Key="OpenMenu">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="Menu">
<EasingDoubleKeyFrame Value="70" KeyTime="0:0:0"/>
<EasingDoubleKeyFrame Value="200" KeyTime="0:0:0.5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="CloseMenu">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="Menu">
<EasingDoubleKeyFrame Value="200" KeyTime="0:0:0"/>
<EasingDoubleKeyFrame Value="70" KeyTime="0:0:0.5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="OpenMenuButton">
<BeginStoryboard Storyboard="{StaticResource OpenMenu}"/>
</EventTrigger>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="CloseMenuButton">
<BeginStoryboard Storyboard="{StaticResource CloseMenu}"/>
</EventTrigger>
</Window.Triggers>
The navigation part with buttons:
<Grid Grid.Row="1" HorizontalAlignment="Left" Width="70" Background="CornflowerBlue" x:Name="Menu">
<StackPanel>
<Grid>
<Button Style="{DynamicResource MaterialDesignFloatingActionButton}"
Background="{x:Null}" BorderBrush="{x:Null}" x:Name="OpenMenuButton" Click="ToggleMenu"
HorizontalAlignment="Right" Width="70">
<md:PackIcon Kind="Menu" Width="35" Height="35"/>
</Button>
<Button Style="{DynamicResource MaterialDesignFloatingActionButton}"
Background="{x:Null}" BorderBrush="{x:Null}" Visibility="Collapsed"
x:Name="CloseMenuButton" Click="ToggleMenu" HorizontalAlignment="Right">
<md:PackIcon Kind="ArrowLeft" Width="35" Height="35"/>
</Button>
</Grid>
</StackPanel>
</Grid>
And code-behind for managing visibility:
private void ToggleMenu(object sender, RoutedEventArgs e)
{
ToggleButtonVisibility(OpenMenuButton);
ToggleButtonVisibility(CloseMenuButton);
}
private void ToggleButtonVisibility(Button b)
{
if (b.Visibility == Visibility.Collapsed || b.Visibility == Visibility.Hidden)
b.Visibility = Visibility.Visible;
else
b.Visibility = Visibility.Collapsed;
}
Is there a way to implement this in respect to MVVM pattern (no code-behind) and to keep click actions in one place (because right now they are split in 2 parts: animation + visibility toggle)?
Add a bool flag to the viewmodel (e.g. IsAnimationStarted)
And then just bind it to buttons visibility with converter
<UserControl.Resources>
..
<local:InvertableBooleanToVisibilityConverter x:Key="bool2visible" />
..
</UserControl.Resources>
..
<Grid>
<Button Style="{DynamicResource MaterialDesignFloatingActionButton}"
Background="{x:Null}" BorderBrush="{x:Null}" x:Name="OpenMenuButton"
Visibility="{Binding IsAnimationStarted, Converter={StaticResource bool2visible}, ConverterParameter=Inverted}"
HorizontalAlignment="Right" Width="70">
<md:PackIcon Kind="Menu" Width="35" Height="35"/>
</Button>
<Button Style="{DynamicResource MaterialDesignFloatingActionButton}"
Background="{x:Null}" BorderBrush="{x:Null}" Visibility="Collapsed"
x:Name="CloseMenuButton"
Visibility="{Binding IsAnimationStarted, Converter={StaticResource bool2visible}, ConverterParameter=Normal}"
HorizontalAlignment="Right">
<md:PackIcon Kind="ArrowLeft" Width="35" Height="35"/>
</Button>
</Grid>
Visibility converter:
https://stackoverflow.com/a/2427307/6468720
I have a event trigger.
I want it to be enabled only if condition occures
for example only if Viewmodel.IsEnabled propery is true AND EventTrigger RoutedEvent="Window.Loaded" occured
my problem is that MultiDataTrigger and MultiTriggers cannot combine Event trigger with Data Trigger.
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="Window.Loaded" SourceName="NotificationWindow">
<BeginStoryboard x:Name="FadeInStoryBoard">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="NotificationWindow" From="0.01" To="1" Storyboard.TargetProperty="Opacity" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</DataTemplate.Triggers>
In other words I have a trigger to load a story board when window is loaded.
I want to be able to enable/disable this trigger per item.
You can use Blend Interactivity for WPF for accomplishing you task. I do not know your whole DataTemplate, so in my sample I will use an invented one.
Let's suppose I have a collection of Person objects and I want to start the DoubleAnimation just per Person whose property IsEnabled is true. I bind my collection to an ItemsControl and I create a "conditional" DataTemplate:
<ItemsControl ItemsSource="{Binding Path=People}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Name="Border" BorderBrush="Gray" BorderThickness="1" CornerRadius="4" Margin="2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding IsEnabled}" RightOperand="True"/>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ControlStoryboardAction ControlStoryboardOption="Play">
<ei:ControlStoryboardAction.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Border" From="0.01" To="1" Storyboard.TargetProperty="Opacity" Duration="0:0:2"/>
</Storyboard>
</ei:ControlStoryboardAction.Storyboard>
</ei:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Text="{Binding Path=Surname, Mode=OneWay}" Margin="2" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Of course you have to declare those namespaces in your XAML:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
The ConditionBehavior object evaluates the ComparisonCondition: if the former is true, it allows the ControlStoryboardAction to run.
I hope this small sample can give you an hint for solving your issue.
I've worked with Opacity property in storyboard
but I cant figure it out how to move an UI element like grid stackpanel button ..... in c#?
(I am writing the storyboard in c# not in xaml )
Well, that depends on your actual layout: Do you want to animate a button in a Grid or in a Canvas (could animate the Margin property or the Canvas.Left attached property, respectively)? Do you want to animate the property itself or a transform (the latter would animate a RenderTransform - specifically a TranslateTransform). You would use the RenderTransform if you still want to refer to the "old" position.
One simple way is:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(Canvas.Left)" From="1" To="350"
Duration="0:0:10" BeginTime="0:0:0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Canvas x:Name="myCanvas" Background="Yellow">
<Button x:Name="myButton" Width="100" Height="30" Canvas.Left="100" Canvas.Top="100" />
</Canvas>
</Grid>
</Window>
it would be better if you use blend for storyboard ..i have genrated a code for stackpanel movement towards right ..just check it..
you can go through this video aslo it's very good it will perfectly work in your case
<Page.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="hello">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="100"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="hello" Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" >
<StackPanel.RenderTransform>
<CompositeTransform/>
</StackPanel.RenderTransform>
<TextBlock Text="hello1" FontSize="50" />
<Button Content="Button" FontSize="50" Click="Button_Click_1" />
</StackPanel>
</Grid>
and to start do this on button click..
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
}
for better understand just read about how to use blend..
Okay I made a Scolling canvas (sometimes I put buttons in it that open my programs or do other stuff) it is working perfectly. But I tried making it into a .dll but I noticed that the method I am using is worthless for a .dll as it autoscrolls upon drop and I can't add more to it. so what I want is a empty canvas (or anything really) that auto-scrolls the content and will let me add more items into it. example: buttons, text block, labels etc. and it will scroll all of them.
Edit: I want to be able to drag the control from the toolbox into the window and then add buttons etc onto it and it will auto-scroll them.
Example below. xaml only.. thinking to make it the way I want it has to be coded in c# not xaml. since once it is added as a user control you cannot add other controls, toolbox items to it and expect them to auto-scroll..
<Canvas ClipToBounds="True" x:Name="scrollerCanvas" Height="588">
<Grid x:Name="OurContainer" Height="588" Background="{x:Null}" ClipToBounds="False">
<Grid.Clip>
<RectangleGeometry Rect="0,0,1087,588" RadiusX="30" RadiusY="30" />
</Grid.Clip>
<StackPanel Height="800" Margin="1">
<StackPanel.RenderTransform>
<TranslateTransform x:Name="scroll" />
</StackPanel.RenderTransform>
</StackPanel>
<Grid.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation
From="620" To="-450"
Storyboard.TargetName="scroll" Storyboard.TargetProperty="Y"
Duration="0:0:28" SpeedRatio=".8" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
</Grid>
</Canvas>
you can use a ScrollViewer with a Canvas inside it.
I'm new to Storyboard animations but I think this might be a problem I can't workaround the easy way. Nevertheless I try my luck here, maybe some of you guys know how to help me.
My Scenario : I want to show a popup in my Application that has a fadein effect. I also want to do this via MVVM so my control that wraps the fadein effect and the popup should no use codebehind and my application should just need to reset the datacontext of this control to a new viewmodel to show a new message.
My Problem is that I cannot determine when the animation is finished because I need to set the fadein Animation in the style.
My XAML looks like this :
<UserControl.Resources>
<Style x:Key="popupStyle" TargetType="{x:Type Border}" >
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard x:Name="FadingStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.05" To="1" BeginTime="0:0:1" Duration="0:0:2.5" >
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="5" EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" BeginTime="0:0:6" Duration="0:0:8.5" >
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="15" EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Popup Name="Popup" IsOpen="{Binding IsVisible}" Height="{Binding PopupHeight}" Width="{Binding PopupWidth}" VerticalOffset="{Binding PopupVerticalOffset}" HorizontalOffset="{Binding PopupHorizontalOffset}" PopupAnimation="Fade" AllowsTransparency="True">
<Border Style="{StaticResource popupStyle}" Name="PopupContent" Padding="1" BorderBrush="#000000" Background="AliceBlue" CornerRadius="5" BorderThickness="3,3,3,3">
<!-- Events -->
<interact:Interaction.Triggers>
<interact:EventTrigger EventName="PreviewMouseDown">
<cmd:EventToCommand Command="{Binding Path=PopupMouseDownCommand}" PassEventArgsToCommand="True" />
</interact:EventTrigger>
</interact:Interaction.Triggers>
<DockPanel Name="ContentContainer" Background="Black" LastChildFill="True">
<Image Source="{Binding MessageIcon}" DockPanel.Dock="Left" Margin="5,0,5,0" Width="32" Height="32" />
<StackPanel Background="Transparent" DockPanel.Dock="Right" Margin="3">
<TextBlock Name="PopupHeaderTextBlock" Margin="0,3,0,5" TextWrapping="Wrap" FontSize="10" Text="{Binding PopupHeaderText}" Foreground="White" Background="Transparent" />
<TextBlock Name="PopupTextBlock" Text="{Binding PopupText}" TextWrapping="Wrap" FontSize="10" Foreground="White" Background="Transparent" />
</StackPanel>
</DockPanel>
</Border>
</Popup>
Anyone any ideas how I can get a notification in my ViewModel when the Storyboard has finished ?
You can handle the Completed event on the storyboard.
Documentation Here: http://msdn.microsoft.com/en-us/library/system.windows.media.animation.timeline.completed.aspx
Here's the code to attach the event from the codebehind:
call from the constructor:
private void AttachToCompletedEvent()
{
Style popupStyle = Resources["popupStyle"];
TriggerBase trigger = popupStyle.Triggers[0];
BeginStoryboard action = trigger.EnterActions[0] as BeginStoryboard;
Storyboard storyboard = action.Storyboard;
storyboard.Completed += CompletedEventHandler;
}
I think that should work for the code you provided.