Animate input box in UWP - xaml

I want to animate input box just like the one above how to do it in MVVM template 10
I have a list view
and need the search bar just like the image

I have attached an solution to your problem. There are two storyboards that are triggered on GotFocus and Lost Focus for an AutoSuggestBox in UWP c#
Here us what I achieved:
XAML :
<Page.Resources>
<Storyboard x:Name="OnCancel">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="70">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="51"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-36.058"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="OnTextBoxFocus">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="70">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:0.4" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="HeaderGrid" d:IsOptimized="True"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-36.058"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid x:Name="HeaderGrid" Margin="0,0,-1,-0.117" RenderTransformOrigin="0.5,0.5" Height="51">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="TextBlock" Margin="5,0,1,3" FontSize="36" SelectionHighlightColor="{x:Null}" Foreground="DodgerBlue"/>
<TextBox Width="1" Height="1" IsReadOnly="True"/>
<Path Data="M0,48 L360,48" Height="1" Margin="0,0,0,0.117" Stretch="Fill" Stroke="DodgerBlue" UseLayoutRounding="False" VerticalAlignment="Bottom" d:LayoutOverrides="LeftPosition, RightPosition"/>
</Grid>
<StackPanel Grid.Row="1">
<Grid Height="32" Margin="12,8,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<AutoSuggestBox x:Name="searchText" PlaceholderText="Search" QueryIcon="Find" TextMemberPath="name" LostFocus="searchText_LostFocus" GotFocus="searchText_GotFocus"/>
<Button x:Name="button" Content="Cancel" VerticalAlignment="Stretch" d:LayoutOverrides="Height" Grid.Column="4" Margin="5,0,0,0" Width="70" Click="button_Click"/>
</Grid>
<ListView x:Name="listView" Background="#FFECECEC" Margin="0,8,0,0">
<ListViewItem Content="List View Item 1" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 2" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 3" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 4" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 5" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 6" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 7" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 8" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 9" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 10" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
</ListView>
</StackPanel>
</Grid>
and in code behind XAML.CS
private void searchText_LostFocus(object sender, RoutedEventArgs e)
{
OnCancel.Begin();
}
private void button_Click(object sender, RoutedEventArgs e)
{
OnCancel.Begin();
}
private void searchText_GotFocus(object sender, RoutedEventArgs e)
{
OnTextBoxFocus.Begin();
}
Also dont forget to set width of button = 0 on Initialization.
Hope this helps.

You can use data binding to bind your title and Cancel button's Visibility property to property defined in your ViewModel, as #Raunaq Patel said, the animations are triggered by GotFocus and LostFocus event.
So you can for example code like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="pageHeader" Text="Main Page" Grid.Row="0" Visibility="{Binding IsVisible}" FontSize="30" />
<Grid Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<AutoSuggestBox HorizontalAlignment="Stretch" GotFocus="{x:Bind ViewModel.Search_GotFocus}"
LostFocus="{x:Bind ViewModel.Search_LostFocus}" VerticalAlignment="Stretch"
Width="{Binding BoxWidth}" />
<TextBlock Text="Cancel" Foreground="BlueViolet" Tapped="{x:Bind ViewModel.Cancel_Tapped}" Width="100"
VerticalAlignment="Stretch" HorizontalAlignment="Center" FontSize="20"
Visibility="{Binding CancelIsVisible}" Grid.Column="1" />
</Grid>
<ListView Grid.Row="1" IsEnabled="{Binding ListViewEnable}">
<ListViewItem>Item 1</ListViewItem>
<ListViewItem>Item 2</ListViewItem>
<ListViewItem>Item 3</ListViewItem>
<ListViewItem>Item 4</ListViewItem>
<ListViewItem>Item 5</ListViewItem>
</ListView>
</Grid>
</Grid>
Since you are using Template 10, code behind is for example in the MainPageViewModel like this:
public class MainPageViewModel : ViewModelBase
{
private Visibility _IsVisible;
public Visibility IsVisible
{
get { return _IsVisible; }
set
{
if (value != _IsVisible)
{
_IsVisible = value;
RaisePropertyChanged();
}
}
}
private Visibility _CancelIsVisible;
public Visibility CancelIsVisible
{
get { return _CancelIsVisible; }
set
{
if (value != _CancelIsVisible)
{
_CancelIsVisible = value;
RaisePropertyChanged();
}
}
}
private bool _ListViewEnable;
public bool ListViewEnable
{
get { return _ListViewEnable; }
set
{
if (value != _ListViewEnable)
{
_ListViewEnable = value;
RaisePropertyChanged();
}
}
}
private double _BoxWidth;
public double BoxWidth
{
get { return _BoxWidth; }
set
{
if (value != _BoxWidth)
{
_BoxWidth = value;
RaisePropertyChanged();
}
}
}
public MainPageViewModel()
{
_IsVisible = Visibility.Visible;
_CancelIsVisible = Visibility.Collapsed;
_ListViewEnable = true;
_BoxWidth = Window.Current.Bounds.Width;
}
public void Search_GotFocus(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
IsVisible = Visibility.Collapsed;
CancelIsVisible = Visibility.Visible;
ListViewEnable = false;
BoxWidth = _BoxWidth - 100;
}
public void Search_LostFocus(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
IsVisible = Visibility.Visible;
CancelIsVisible = Visibility.Collapsed;
ListViewEnable = true;
BoxWidth = Window.Current.Bounds.Width;
}
public void Cancel_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
IsVisible = Visibility.Visible;
CancelIsVisible = Visibility.Collapsed;
ListViewEnable = true;
BoxWidth = Window.Current.Bounds.Width;
}
}
Here you can see the data in ListView are fake, you can of course use DataTemplate and bind collection to the ItemSource of the ListView. Here is the rendering image of my sample:

It's AutoSuggestBox.
You can see how to use in https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlAutoSuggestBox
And you can see summary on https://msdn.microsoft.com/zh-cn/windows/uwp/controls-and-patterns/auto-suggest-box?f=255&MSPPError=-2147217396

Related

How to generate Storyboard dynamically in uwp

I have a scenario where I have to generate create same StoryBoard Animation in Xaml for a set of data(which I will bind form ViewModel).
<Page
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
xmlns:miControls="using:Microsoft.UI.Xaml.Controls">
<Page.Resources>
<miControls:ItemsRepeater x:Name="repmeaterTest">
<miControls:ItemsRepeater.ItemTemplate>
<DataTemplate>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetName="DemoCircle" Storyboard.TargetProperty="(FrameworkElement.Width)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="50"/>
<EasingDoubleKeyFrame KeyTime="00:00:04" Value="250"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetName="DemoCircle" Storyboard.TargetProperty="(FrameworkElement.Height)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="50"/>
<EasingDoubleKeyFrame KeyTime="00:00:04" Value="250"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate>
</miControls:ItemsRepeater.ItemTemplate>
</miControls:ItemsRepeater>
</Page.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="clikToAnimate" Content="Animate" Click="clikToAnimate_Click" Margin="10"/>
<Ellipse Name="DemoCircle" Stroke="Purple" Width="50" Height="50" StrokeThickness="4" Fill="AntiqueWhite"/>
</StackPanel>
public sealed partial class MainPage : Page
{
List<int> noOfStoryBoard = new List<int> { 1,2,3,4,5};
public MainPage()
{
this.InitializeComponent();
}
private void clikToAnimate_Click(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
}
}
I want to generate StoryBoard dynamically for noOfStoryBoard(ie 5) in xaml
Does anyone have idea kindly share,
Here what i have tried to use items repeater

How to animate ListItem in ItemClick?

I am having Storyboard in my Page resources to share it between required controls. I try to animate clicked ListItem using that Storyboard in code behind by setting TargetName propery.
<Page.Resources>
<Storyboard x:Name="Story1">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="-200"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<ListView x:Name="ListView1" IsItemClickEnabled="True" ItemClick="ListView1_ItemClick">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridData">
<Grid.RenderTransform>
<TranslateTransform x:Name="GridTrans" X="0" />
</Grid.RenderTransform>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Price}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void ListView1_ItemClick(object sender, ItemClickEventArgs e)
{
Story1.Stop();
var item = ListView1.ContainerFromItem(e.ClickedItem) as ListViewItem;
var grid = item.ContentTemplateRoot as Grid;
Storyboard.SetTargetName(Story1, grid.Name); //???
Story1.Begin();
}
But unable to animate clicked ListItem on ItemClick event. I get error as "Cannot resolve TargetName GridData"
The GridData is under DataTemplate, if you use SetTargetName method to set animation, it will not get correct ContentTemplateRoot. For your requirement, you could use SetTarget method.
private void ListView1_ItemClick(object sender, ItemClickEventArgs e)
{
Story1.Stop();
var item = ListView1.ContainerFromItem(e.ClickedItem) as ListViewItem;
var grid = item.ContentTemplateRoot as Grid;
Storyboard.SetTarget(Story1, grid);
Story1.Begin();
}

Animating Xaml Grid.ColumnDefinitions using XAML Behaviors when Binding Changes

I have a grid showing data received from a web service as below:
The graph bars are achieved using data binding, with the converter returning a GridLength Star value:
<Grid Grid.Row="1" BorderThickness="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="{Binding home.possessionPercentage, Converter={StaticResource statswidthConverter}}"/>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="{Binding away.possessionPercentage, Converter={StaticResource statswidthConverter}}"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tbl1" HorizontalAlignment="Center" TextWrapping="Wrap" Text="{Binding home.possessionPercentage}"/>
<Rectangle Fill="#FF1DEE00" Stroke="White" Grid.Column="1" StrokeThickness="0"/>
<Rectangle Fill="White" Stroke="White" Grid.Column="2" StrokeThickness="0"/>
<Rectangle Fill="#FF139D00" Stroke="White" Grid.Column="3" StrokeThickness="0"/>
<TextBlock x:Name="tbr1" HorizontalAlignment="Center" TextWrapping="Wrap" Text="{Binding away.possessionPercentage}" Grid.Column="4"/>
</Grid>
What I would like to achieve is for the column sizes to be animated to the new value when the binding value is updated rather than just a jump to the new size. I believe this can be achieved with the Microsoft.Behaviors library - https://github.com/Microsoft/XamlBehaviors/ but am unsure where to start. Any advice please?
To meet your requirements, firstly you need an animation to animate the Width property. I wrote a simple demo which use DoubleAnimation to animate the Width of the Rectangle. For the reason I set the target of storyboard to Rectangle is that ColumnDefinition.Width property is GridLength type that we cannot use DoubleAnimation.
Secondly, we need a trigger to trigger the animation. Here I use DataTriggerBehavior in XamlBehaviors SDK. Once the data greater than one value the trigger can be triggered.Completed demo as follows.
<Page
...
xmlns:Interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Media="using:Microsoft.Xaml.Interactions.Media">
<Page.Resources>
<local:statswidthConverter x:Name="statswidthConverter" />
<Storyboard x:Name="Increase">
<DoubleAnimation
Duration="0:0:5"
EnableDependentAnimation="true"
Storyboard.TargetName="rec1"
Storyboard.TargetProperty="Width"
To="{Binding homePercentage, Converter={StaticResource statswidthConverter}}" />
</Storyboard>
<Storyboard x:Name="decrease">
<DoubleAnimation
Duration="0:0:5"
EnableDependentAnimation="true"
Storyboard.TargetName="rec2"
Storyboard.TargetProperty="Width"
To="{Binding awayPercentage, Converter={StaticResource statswidthConverter}}" />
</Storyboard>
</Page.Resources>
<StackPanel
Padding="50"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="Grid_Loaded">
<Grid
Grid.Row="1"
Height="50"
BorderThickness="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition x:Name="clo1" Width="Auto" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBlock
x:Name="tbl1"
HorizontalAlignment="Center"
Text="{Binding homePercentage}"
TextWrapping="Wrap" />
<Rectangle
x:Name="rec1"
Grid.Column="1"
Width="0"
Fill="#FF1DEE00"
Stroke="White"
StrokeThickness="0">
<Interactivity:Interaction.Behaviors>
<Interactions:DataTriggerBehavior
Binding="{Binding homePercentage}"
ComparisonCondition="GreaterThan"
Value="0">
<Media:ControlStoryboardAction Storyboard="{StaticResource Increase}" />
</Interactions:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Rectangle>
<Rectangle
Grid.Column="2"
Fill="White"
Stroke="White"
StrokeThickness="0" />
<Rectangle
x:Name="rec2"
Grid.Column="3"
Width="200"
Fill="#FF139D00"
Stroke="White"
StrokeThickness="0" >
<Interactivity:Interaction.Behaviors>
<Interactions:DataTriggerBehavior
Binding="{Binding awayPercentage}"
ComparisonCondition="LessThan"
Value="200">
<Media:ControlStoryboardAction Storyboard="{StaticResource decrease}" />
</Interactions:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Rectangle>
<TextBlock
x:Name="tbr1"
Grid.Column="4"
HorizontalAlignment="Center"
Text="{Binding awayPercentage}"
TextWrapping="Wrap" />
</Grid>
</StackPanel>
</Page>
Code behind
public sealed partial class MainPage : Page
{
ObservableCollection<Percentage> percentages;
public MainPage()
{
this.InitializeComponent();
percentages = new ObservableCollection<Percentage>()
{
new Percentage {homePercentage=63,awayPercentage=37 }
};
this.DataContext = percentages[0];
}
}
public class Percentage
{
public double homePercentage { get; set; }
public double awayPercentage { get; set; }
}
public class statswidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (double)value * 2;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return (double)value / 2;
}
}
If you still want to set animation for ColumnDefinition.Width please use ObjectAnimationUsingKeyFrames which don't have so smoothly effects as DoubleAnimation the demo showed. To be smoothly need quite a lot frames. For example:
<Storyboard x:Name="storyobejct">
<ObjectAnimationUsingKeyFrames
Duration="0:0:3"
Storyboard.TargetName="clo1"
Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="1" />
<DiscreteObjectKeyFrame KeyTime="0:0:1" Value="50" />
<DiscreteObjectKeyFrame KeyTime="0:0:1.5" Value="60" />
<DiscreteObjectKeyFrame KeyTime="0:0:2.0" Value="100" />
<DiscreteObjectKeyFrame KeyTime="0:0:3" Value="126" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
Using which animation and which trigger depend on your layout and requirements. Pay attention that animating the Width seems to be a dependent animation which is not recommended. More details animation please reference Animations overview, more details about XAML behavior please reference this document.

UWP - Storyboard in DataTemplate ControlStoryboardAction fires only first time

The request is that the row of my ListView blinks when the property SelectedItem of the ViewModel raises change.
This is my code, the problem is that it works only first time. Subsequent changes are ignored.
<DataTemplate x:Key="myDataTemplate">
<Grid x:Name="myGrid">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding SelectedItem}" Value="True">
<Media:ControlStoryboardAction>
<Media:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
To="#009ABF"
Storyboard.TargetName="myGrid"
Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"
AutoReverse="True"
Duration="0:0:1"
RepeatBehavior="1x" />
</Storyboard>
</Media:ControlStoryboardAction.Storyboard>
</Media:ControlStoryboardAction>
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<TextBlock Text="{Binding Name}"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Margin="0,2,10,0"
FontSize="16"
TextAlignment="Left"/>
<!--OMISSIS-->
</Grid>
SelectedItem code :
public bool SelectedItem
{
get
{
return this.selectedItem;
}
set
{
this.selectedItem = value;
this.RaisePropertyChanged();
}
}
This is the solution i found.
1) Use Completed event of the Storyboard
<Storyboard Completed="SelectedItemReset" FillBehavior="Stop">
3) Use the GalaSoft.MvvmLight.Messaging.Messenger to comunicate from CodeBehind and ViewModel the reset of the property SelectedItem
Xaml
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="DataTemplateGrid">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding SelectedItem}" ComparisonCondition="Equal" Value="True">
<Media:ControlStoryboardAction ControlStoryboardOption="Play">
<Media:ControlStoryboardAction.Storyboard>
<Storyboard Completed="SelectedItemReset" FillBehavior="Stop">
<ColorAnimation
To="Lime"
Storyboard.TargetName="DataTemplateGrid"
Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"
Duration="0:0:1"/>
</Storyboard>
</Media:ControlStoryboardAction.Storyboard>
</Media:ControlStoryboardAction>
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<!--OMISSIS-->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
CodeBehind
private void SelectedItemReset(object sender, object e)
{
GalaSoft.MvvmLight.Messaging.Messenger.Default.Send<Mvvm.ViewModels.Units.SelectedItemResetMessage>(new Mvvm.ViewModels.Units.SelectedItemResetMessage());
}
MVVM Class .ctor
public MyViewModel()
{
GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<SelectedItemResetMessage>(this, message =>
{
if (this.SelectedItem == true)
this.SelectedItem = false;
});
}
Note: My DataTemplate was in a separate file and linked to the ListView with the ItemTemplate property, this prevented me from calling the method Completed in CodeBehind.

How to create dynamically menu in MVVM

I'm working on a simple WPF project, using MVVM.
I want to create a menu with dynamically Items.
Its my xaml file:
<Menu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header"
Value="{Binding MenuText}" />
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding MenuIcon}"
Height="16px"
Width="16px" />
</Setter.Value>
</Setter>
<Setter Property="ItemsSource"
Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding DataContext.ClickCommand , RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Menu}}"></Setter>
<Setter Property="CommandParameter" Value="{Binding ItemCommandParameter}"></Setter>
</Style>
</Menu.Resources>
And It's the view model class that is content of my xaml file:
private ObservableCollection<MenuItemModel> _topMenuItems;
public ObservableCollection<MenuItemModel> TopMenuItems
{
get { return _topMenuItems; }
set
{
if (_topMenuItems == value)
return;
Set("TopMenuItems", ref _topMenuItems, value);
}
}
public void LoadMainMenu()
{
IList<Model.MenuItemModel> fileMenuItems = PopulateFileMenuEntries();
_topMenuItems = new ObservableCollection<MenuItemModel>();
_topMenuItems.Add(new MenuItemModel() { MenuText = "_File", Children = new ObservableCollection<MenuItemModel>(fileMenuItems) });
}
IList<MenuItemModel> PopulateFileMenuEntries()
{
List<MenuItemModel> fileMenuItems = new List<MenuItemModel>();
fileMenuItems.Add(new MenuItemModel() { MenuText = "_Theme" });
fileMenuItems.Add(new MenuItemModel() { MenuText = "_Exit" });
return fileMenuItems;
}
my Menu Item Model Class:
public class MenuItemModel : ObservableObject
{
private string _menuText;
public string MenuText
{
get { return _menuText; }
set
{
if (_menuText == value)
return;
Set("MenuText", ref _menuText, value);
}
}
private BitmapImage _menuIcon;
public BitmapImage MenuIcon
{
get { return _menuIcon; }
set
{
if (_menuIcon == value)
return;
Set("MenuIcon", ref _menuIcon, value);
}
}
private ObservableCollection<MenuItemModel> _children;
public ObservableCollection<MenuItemModel> Children
{
get { return _children; }
set
{
Set("Children", ref _children, value);
}
}
public string ItemCommandParameter { get; set; }
}
My question is here:
How can I fill menu Items dynamically instead of using PopulateFileMenuEntries method. For example I want to have just a List Collection that is get the proper menu Items from database. How can I assign this list collection to the menu items in my sample project? I have 2 menu Items with subItems:
Main : Student, Teacher, Course,...
File : Theme, Exit,...
I hope you will get idea from this
<Style TargetType="expanderControl:ExpanderControl">
<Setter Property="HorizontalAlignment"
Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="expanderControl:ExpanderControl">
<Grid>
<Grid.Resources>
<QuadraticEase x:Key="QuadraticEaseOut"
EasingMode="EaseOut"/>
<QuadraticEase x:Key="QuadraticEaseInOut"
EasingMode="EaseInOut"/>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="41" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpansionStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Collapsed"
GeneratedDuration="0:0:0.15"
To="Expanded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="ItemsCanvas"
EnableDependentAnimation="True">
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseOut}"
KeyTime="0:0:0.00"
Value="0" />
<EasingDoubleKeyFrame x:Name="CollapsedToExpandedKeyFrame"
EasingFunction="{StaticResource QuadraticEaseOut}"
KeyTime="0:0:0.15"
Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Duration="0"
To="1.0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ItemsCanvas" />
</Storyboard>
</VisualTransition>
<VisualTransition From="Expanded"
GeneratedDuration="0:0:0.15"
To="Collapsed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="ItemsCanvas"
EnableDependentAnimation="True">
<EasingDoubleKeyFrame x:Name="ExpandedToCollapsedKeyFrame"
EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.00"
Value="1" />
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.15"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ItemsCanvas">
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.00"
Value="1.0" />
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.15"
Value="0.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="ItemsCanvas"
EnableDependentAnimation="True">
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.00"
Value="0.0" />
<EasingDoubleKeyFrame EasingFunction="{StaticResource QuadraticEaseInOut}"
KeyTime="0:0:0.15"
Value="-35" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimation Duration="0"
To="0"
Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="ItemsCanvas" />
<DoubleAnimation Duration="0"
To="0.0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ItemsCanvas" />
</Storyboard>
</VisualState>
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimation Duration="0"
Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="ItemsCanvas" />
<DoubleAnimation Duration="0"
To="1.0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="ItemsCanvas" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ExpandabilityStates">
<VisualState x:Name="Expandable" />
<VisualState x:Name="NonExpandable">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="ExpandableContent">
<DiscreteObjectKeyFrame KeyTime="0:0:0.0"
Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="NonExpandableContent">
<DiscreteObjectKeyFrame KeyTime="0:0:0.0"
Value="Visible" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ListViewItem x:Name="ExpandableContent" Background="Transparent"
Grid.ColumnSpan="2"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="41" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl x:Name="Header"
Grid.ColumnSpan="2"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Content="{TemplateBinding Header}"
Grid.Column="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Grid.Row="0" />
<ContentControl x:Name="Expander"
ContentTemplate="{TemplateBinding ExpanderTemplate}"
Content="{TemplateBinding Expander}"
Grid.Column="1"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Margin="11,0,0,0"
Grid.Row="1" />
<Grid x:Name="ExpanderPanel"
Background="Transparent"
Grid.ColumnSpan="2"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
/>
<StackPanel Height="1" Background="Black" Grid.ColumnSpan="2"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2" VerticalAlignment="Bottom"></StackPanel>
</Grid>
</ListViewItem>
<ContentControl x:Name="NonExpandableContent"
Grid.ColumnSpan="2"
ContentTemplate="{TemplateBinding NonExpandableHeaderTemplate}"
Content="{TemplateBinding NonExpandableHeader}"
Grid.Column="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Grid.Row="0"
Grid.RowSpan="2"
Visibility="Collapsed" />
<Canvas x:Name="ItemsCanvas"
Grid.Column="1"
Margin="-120,0,0,0"
Opacity="0.0"
Grid.Row="2"
Width="{Binding ActualWidth, ElementName=Presenter}"
Height="{Binding ActualHeight, ElementName=Presenter}">
<Canvas.RenderTransform>
<CompositeTransform TranslateY="0.0" />
</Canvas.RenderTransform>
<ItemsPresenter x:Name="Presenter" />
</Canvas>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>