Storyboard Completed Event from Style? - c#

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.

Related

Parameterized ResourceDictionary - is this possible?

I want to create a control that's composed of a number of circling Ellipse objects, like this (excerpt):
<Canvas Width="100" Height="100">
<Canvas Width="100" Height="100">
<Ellipse Canvas.Left="46"
Width="8"
Height="8"
Fill="White" />
<Canvas.RenderTransform>
<RotateTransform x:Name="r0" Angle="0" CenterX="50" CenterY="50" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="0:0:0"
Storyboard.TargetName="r0"
Storyboard.TargetProperty="Angle"
To="360"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
<Canvas Width="100" Height="100">
<Ellipse Canvas.Left="46"
Canvas.Top="10"
Width="8"
Height="8"
Fill="White" />
<Canvas.RenderTransform>
<RotateTransform x:Name="r1" Angle="0" CenterX="50" CenterY="50" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="0:0:0.05"
Storyboard.TargetName="r1"
Storyboard.TargetProperty="Angle"
To="360"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
<Canvas Width="100" Height="100">
<Ellipse Canvas.Left="46"
Canvas.Top="20"
Width="8"
Height="8"
Fill="White" />
<Canvas.RenderTransform>
<RotateTransform x:Name="r2" Angle="0" CenterX="50" CenterY="50" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="0:0:0.1"
Storyboard.TargetName="r2"
Storyboard.TargetProperty="Angle"
To="360"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
<!-- ... -->
</Canvas>
Please note: All of the inner Canvas/Ellipse elements differ by:
Ellipse.Canvas.Top
RotateTransform.Name
DoubleAnimation.BeginTime
Now, I want to save me a lot of writing by creating a resource composed of:
The inner Canvas
The Ellipse therein
The RotateTransform therein
The EventTrigger therein
The DoubleAnimation within the Eventtrigger
My final control would rather resemble something like this:
<Canvas Width="100" Height="100">
{StaticResource myElem InnerTop=0, BeginTime="0:0:0.0"}
{StaticResource myElem InnerTop=10, BeginTime="0:0:0.05"}
{StaticResource myElem InnerTop=20, BeginTime="0:0:0.1"}
</Canvas>
Is something like this possible by utilizing Resources only?
Or do I need to create a custom control, run by Code-Behind properties, to achieve this?
In the following I will describe two approaches to your issue using data templating or a UserControl.
Items Control and Data Templates
You can create a small utility type that exposes the properties that you want to customize.
public class CirclingEllipseProperties
{
public double Top { get; set; }
public TimeSpan BeginTime { get; set; }
}
Create a data template for the circling ellipse item that binds these properties.
<DataTemplate x:Key="CirclingEllipseTemplate" DataType="{x:Type local:CirclingEllipseProperties}">
<Canvas Width="100" Height="100">
<Ellipse Canvas.Left="46"
Canvas.Top="{Binding Top}"
Width="8"
Height="8"
Fill="White" />
<Canvas.RenderTransform>
<RotateTransform x:Name="r0" Angle="0" CenterX="50" CenterY="50" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="{Binding BeginTime}"
Storyboard.TargetName="r0"
Storyboard.TargetProperty="Angle"
To="360"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
</DataTemplate>
Create an ItemsControl with a Canvas as ItemsPanel. Assign the data template as ItemTemplate and add an x:Array with CirclingEllipseProperties for each element as ItemsSource. You could even bind a collection of these elements from a view model or code-behind dynamically.
<ItemsControl Width="100"
Height="100"
ItemTemplate="{StaticResource CirclingEllipseTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<x:Array Type="{x:Type local:CirclingEllipseProperties}">
<local:CirclingEllipseProperties BeginTime="0:0:0" Top="0" />
<local:CirclingEllipseProperties BeginTime="0:0:0.05" Top="10" />
<local:CirclingEllipseProperties BeginTime="0:0:0.1" Top="20" />
</x:Array>
</ItemsControl.ItemsSource>
</ItemsControl>
Of course, you can also create a style for the ItemsControl, if you want to reuse it.
<Style x:Key="CirclingEllipseItemsControlStyle" TargetType="{x:Type ItemsControl}">
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="100" />
<Setter Property="ItemTemplate" Value="{StaticResource CirclingEllipseTemplate}" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsControl Style="{StaticResource CirclingEllipseItemsControlStyle}">
<ItemsControl.ItemsSource>
<!-- ...items source as above. -->
</ItemsControl.ItemsSource>
</ItemsControl>
Create a User Control
Create a custom UserControl that exposes properties for Top and BeginTime.
<UserControl x:Class="YourApp.CirclingEllipseUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:YourApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="100"
Height="100"
mc:Ignorable="d">
<Canvas>
<Ellipse Canvas.Left="46"
Canvas.Top="{Binding Top, RelativeSource={RelativeSource AncestorType={x:Type local:CirclingEllipseUserControl}}}"
Width="8"
Height="8"
Fill="White" />
<Canvas.RenderTransform>
<RotateTransform x:Name="r0" Angle="0" CenterX="50" CenterY="50" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="{Binding BeginTime, RelativeSource={RelativeSource AncestorType={x:Type local:CirclingEllipseUserControl}}}"
Storyboard.TargetName="r0"
Storyboard.TargetProperty="Angle"
To="360"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
</UserControl>
public partial class CirclingEllipseUserControl : UserControl
{
public static readonly DependencyProperty BeginTimeProperty = DependencyProperty.Register(
"BeginTime", typeof(TimeSpan), typeof(CirclingEllipseUserControl), new PropertyMetadata(TimeSpan.Zero));
public static readonly DependencyProperty TopProperty = DependencyProperty.Register(
"Top", typeof(double), typeof(CirclingEllipseUserControl), new PropertyMetadata(0.0));
public double Top
{
get => (double)GetValue(TopProperty);
set => SetValue(TopProperty, value);
}
public TimeSpan BeginTime
{
get => (TimeSpan)GetValue(BeginTimeProperty);
set => SetValue(BeginTimeProperty, value);
}
public CirclingEllipseUserControl()
{
InitializeComponent();
}
}
Add instances of the CirclingEllipseUserControl to your Canvas or create a DataTemplate for it like in the approach above to be able to dynamically bind items.
<Canvas Width="100" Height="100">
<local:CirclingEllipseUserControl BeginTime="0:0:0" Top="0" />
<local:CirclingEllipseUserControl BeginTime="0:0:0.05" Top="10" />
<local:CirclingEllipseUserControl BeginTime="0:0:0.1" Top="20" />
</Canvas>

MVVM and toggling buttons' visibility

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

Why won't my Template's TextBox bind

I am trying to do some binding. For the most part, my MVVM application is working fine but I now want to use a Template. In this case, I'm using XCeed chart which expose a SeriesTemplate.
My code is:
<UserControl
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
x:Class="MyApp.AppUi.View.Graph.GraphView"
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:converter="clr-namespace:MyApp.AppUi.Converters"
>
<Grid>
<Grid.Resources>
<converter:MyIntConverter x:Key="MyIntConverter" />
<DataTemplate x:Key="MyLabelTemplate">
<TextBlock Text="{Binding Path=Text, Converter={StaticResource MyIntConverter}}" />
</DataTemplate>
<!--give it a name, Bind to above, choose property -->
<CollectionViewSource x:Key="GraphDataCollection" Source="{Binding GraphDataList}" />
<Style x:Key="TextBoxTextStyle" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="12"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="FontSize" To="19" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="FontSize" To="12" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}">
<Rectangle RadiusX="5" RadiusY="5" >
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.8" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Rectangle.Triggers>
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#FFffcf26" Offset="0.0" />
<GradientStop Color="#FFff7f04" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter VerticalAlignment="Center" Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="SeriesTemplate">
<Button>
<StackPanel>
<TextBlock Text="{Binding GraphData.ShortDate}" Style="{StaticResource TextBoxTextStyle}" />
</StackPanel>
</Button>
</DataTemplate>
</Grid.Resources>
<GroupBox Header="{Binding Title}">
<GroupBox.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0" >
<GradientStop Offset="0" Color="#FF9d9d9d" />
<GradientStop Offset="1" Color="#FF666666" />
</LinearGradientBrush>
</GroupBox.Background>
<xctk:Chart Height="400" Width="400" ShowLegend="False">
<xctk:Chart.Areas>
<xctk:Area >
<xctk:Area.XAxis>
<xctk:Axis Title="Date"
GraduationMode="Manual"
LabelsType="DateTime"
ScaleMode="Automatic"
TitleMargin="10"
AxisLabelsLayout="ShowAll"
ShowArrow="False"
ShowAxis="True"
ShowGridLines="True"
ShowTicks="True"
ShowTickLabels="True"
ShowAxisLabel="True"
Reversed="False"
/>
</xctk:Area.XAxis>
<xctk:Area.YAxis>
<xctk:Axis Title="Google position"
ScaleMode="Manual"
TitleMargin="10"
AxisLabelsLayout="ShowAll"
ShowArrow="False"
ShowAxis="True"
ShowGridLines="True"
CustomRangeStart="1.00"
CustomRangeEnd="111.00"
ShowTicks="True"
ShowTickLabels="True"
ShowAxisLabel="True"
Reversed="False"
LabelTemplate="{StaticResource MyLabelTemplate}"
/>
</xctk:Area.YAxis>
<xctk:Area.Series>
<xctk:Series DataPointsSource="{Binding Source={StaticResource GraphDataCollection}}"
Template="{StaticResource SeriesTemplate}"
ShowPointsInLegend="true">
<xctk:Series.DataPointBindings>
<xctk:BindingInfo PropertyName="Y">
<xctk:BindingInfo.Binding>
<Binding Path="Position"/>
</xctk:BindingInfo.Binding>
</xctk:BindingInfo>
<xctk:BindingInfo PropertyName="X">
<xctk:BindingInfo.Binding>
<Binding Path="Date"/>
</xctk:BindingInfo.Binding>
</xctk:BindingInfo>
<xctk:BindingInfo PropertyName="Label">
<xctk:BindingInfo.Binding>
<Binding Path="ShortDate"/>
</xctk:BindingInfo.Binding>
</xctk:BindingInfo>
</xctk:Series.DataPointBindings>
</xctk:Series>
</xctk:Area.Series>
</xctk:Area>
</xctk:Chart.Areas>
</xctk:Chart>
</GroupBox>
</Grid>
and my ViewModel
public class GraphViewModel : BaseViewModel
{
public GraphViewModel(List<GraphData> data, string title )
{
this.GraphDataList = data;
this.Title = title;
}
public string Title { get; private set; }
public List<GraphData> GraphDataList { get; private set; }
}
And the DataContext is set in the Resource Dictionary
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:graphView="clr-namespace:MyApp.AppUi.View.Graph"
xmlns:graphViewModel="clr-namespace:MyApp.AppUi.ViewModel.Graph"
xmlns:converter="clr-namespace:MyApp.AppUi.Converters"
>
<DataTemplate DataType="{x:Type graphViewModel:GraphViewModel}">
<graphView:GraphView />
</DataTemplate>
The chart displays as desired but, the SeriesTemplate does not bind. There is an error message in the ouput window, which I understand what the message is saying, but not how to fix it.
The error message is
System.Windows.Data Error: 40 : BindingExpression path error: 'ShortDate' property not found on 'object' ''ColumnPrimitiveInfo' (HashCode=39288004)'. BindingExpression:Path=ShortDate; DataItem='ColumnPrimitiveInfo' (HashCode=39288004); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
How do I get the binding to work for
<DataTemplate x:Key="SeriesTemplate">
<Button x:Name="Bar">
<StackPanel>
<TextBlock Text="{Binding GraphData.ShortDate}" Style="{StaticResource TextBoxTextStyle}" /> <!--THIS IS WHERE THE FAULT IS -->
</StackPanel>
</Button>
</DataTemplate>
XCeed have a working demo with source code, if you download the application, click on Charts -> Styling -> Column Series you can see that my code is very very similar. There's works, but mine does not and I can't see why. Please note, the graph itself displays, it's just the textbox is not showing. However, if I don't use binding, and just use Text="SomeWords" then it works fine
After a few hours of voodoo programming (where I just try different things at random) I found the solution.
<TextBlock Text="{Binding Path=Content.ShortDate}" Style="{StaticResource TextBoxTextStyle}" />
I think this is because of (see the Button Setter in code of OP)
<ContentPresenter VerticalAlignment="Center" Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"/>
Try this:
<DataTemplate x:Key="SeriesTemplate">
<Button>
<StackPanel>
<TextBlock Text="{Binding Path=ShortDate}" Style="{StaticResource TextBoxTextStyle}" />
</StackPanel>
</Button>
</DataTemplate>
From looking at the documentation hereon the XCeed documentation site it appears that you are adding an extra layer of indirection to the binding. Try binding directly to the GraphDataList
<xctk:Series DataPointsSource="{Binding Source={StaticResource GraphDataList}}"
Template="{StaticResource SeriesTemplate}"
ShowPointsInLegend="true">
and then in the series
<DataTemplate x:Key="SeriesTemplate">
<Button>
<StackPanel>
<TextBlock Text="{Binding Path=ShortDate}" Style="{StaticResource TextBoxTextStyle}" />
</StackPanel>
</Button>
</DataTemplate>

how to move UI element with storyboard?

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..

Creating a search box using WPF

I'm trying to create a search box with the controls TextBox and ListBox.
When I'm on the TextBox starting to type an event handler GotFocus open the ListBox.
I want the ListBox to be closed when the TextBox not on focus. I tried to use the LostFocus event in the TextBox, but it didn't work.
In which event handler should I use? I didn't find a good example implements this mechanism.
Edit:
I have something like that:
<Canvas Name="m_MainCanvas" Grid.ColumnSpan="2" >
<Rectangle MouseDown="Canvas_MouseDown" Fill="White" Height="280" HorizontalAlignment="Left" Margin="256,12,0,0" x:Name="m_MainRectangle" RadiusX="0" RadiusY="0" Stroke="Black" StrokeThickness="3" VerticalAlignment="Top" Width="238" />
<TextBox Height="23" Margin="10,0,0,210" Name="m_SearchTextBox" VerticalAlignment="Bottom" BorderThickness="0.5" BorderBrush="#69000000" TextChanged="m_SearchTextBox_TextChanged" FontFamily="Kristen ITC" Text="" FontSize="14" FontWeight="Black" HorizontalAlignment="Left" Width="165" Canvas.Top="86" Canvas.Left="274" LostFocus="m_SearchTextBox_LostFocus"/>
<ListBox ItemTemplate="{DynamicResource ListBoxItemDataTemplate}" ItemsSource="{Binding}" Name="m_FriendsSearchList" Visibility="Hidden" Background="#FFBCEB85" Width="181" Height="193" Canvas.Left="283" Canvas.Top="118">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClickItemToSelect" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The MouseDown event in the Rectangle control is used to get the TextBox out of focus, but it isn't working.
something like:
<StackPanel>
<TextBox>
<TextBox.Triggers>
<EventTrigger RoutedEvent="GotFocus">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0"
Storyboard.TargetName="lb"
Storyboard.TargetProperty="(ListBox.Opacity)"
To="1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="LostFocus">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0"
Storyboard.TargetName="lb"
Storyboard.TargetProperty="(ListBox.Opacity)"
To="0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBox.Triggers>
</TextBox>
<ListBox x:Name="lb"
Opacity="0">
<ListBoxItem Content="A" />
<ListBoxItem Content="B" />
</ListBox>
</StackPanel>
However in the above approach the ListBox is still holding the space it resides in. if we instead toggle Visibility to Collapsed, every-time the ListBox becomes Visible other control's are going to start moving to accomodate that.
To avoid both these cases, such things are normally implemented via a Popup
<StackPanel>
<TextBox x:Name="tb" />
<Popup Width="{Binding RelativeSource={RelativeSource Self},
Path=PlacementTarget.ActualWidth}"
Placement="Bottom"
PlacementTarget="{Binding ElementName=tb}">
<Popup.Style>
<Style TargetType="{x:Type Popup}">
<Setter Property="IsOpen"
Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tb,
Path=IsFocused}"
Value="True">
<Setter Property="IsOpen"
Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
<ListBox>
<ListBoxItem Content="A" />
<ListBoxItem Content="B" />
</ListBox>
</Popup>
</StackPanel>
^^ You'll still see the same output however you no longer have any control's that have to change position due to the popup changing open / close states.
Update:
Download Link
Remember the Trigger is set based on the TextBox having / losing focus. IF you click somewhere that does not take focus, then you will not see the Popup(ListBox) disappear.

Categories

Resources