Display dot-dot-dot progress in a WPF button - wpf

I found quite a few examples for showing progress where the progress bars and wheels are used however; I could find only one javascript example to show an ellipsis (dot-dot-dot) to refer progress hence I thought of asking this question. My app is not very complex - it only has a few check-boxes and one button. Recently my team requested for an enhancement and want to keep it simple as well.
There is a button named 'GO' that the user clicks after configuring the required settings. The code behind it is also really straightforward - it disables the button after the click event and call's a standalone exe using ProcessStartInfo that performs three actions 'reconcle', 'post' and 'publish'. I use the WaitForExist() method to re-enable the button.
I was requested by my team to show the 'current process' on the button. They simply want the button text to show Reconciling. Reconciling.. Reconciling... (at regular intervals say, 1 sec) followed by Posting and Publishing in a similar fashion.
It would be nice to know the most appropriate way to achieve this. Thanks in advance.

The simplest way of doing that is using an ObjectAnimationUsingKeyFrames. Set the TargetProperty on the Content and set the Value of each DiscreteObjectKeyFrame to Reconciling. Reconciling.. Reconciling....
Example for a ControlTemplate with a ContentPresenter named PART_Content:
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Content" Storyboard.TargetProperty="Content" Duration="00:00:00.8" RepeatBehavior="Forever">
<DiscreteObjectKeyFrame KeyTime="00:00:00.0" Value="Loading"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.2" Value="Loading."/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4" Value="Loading.."/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.6" Value="Loading..."/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>

Related

Use a backgroundcolor resource for multiple Components correctly

I created a resourcefile in which I want to hold all colors for my application, so that I can change them later, if my boss decides on the colors that he want to have.
My Problem is in the combination of this approach an the usage of a controltemplate for my ComboboxToggleButton. To be precise: if I hover the mouse the combobox, it should change part if its background, which is a GradientBrush.
The current Code (in the VisualstateManager of the ComboBoxToggleButton) looks like this:
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)"
Storyboard.TargetName="Border">
<EasingColorKeyFrame KeyTime="0" Value="{StaticResource Highlighted_Color}" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
The problem is that this solution changes the color for ALL controls that use the same GradientBrush as a background, not only the color of the control the mouse hovers over.
How can I fix this most easly?
I tryed replacing the Visual States section of the ToggleButton by triggers in the Combobox, but they had no effect.
In the worst case I could go back to the version where the GradientBrush was in every Control directly embedded, so not over a resource from my ColorsAndBrushes file, but that would be rather ugly if I want to change the colors later.
When you define something like a GradientBrush, WPF serves up one instance of that object, which is shared by all of the UI controls that reference it. In effect it's a "singleton", so when the animation is applied to the GradientBrush you'll see the effect in all of the other controls simultaneously.
Try adding x:Shared="False" to the GradientBrush. This will ensure that each control using the GradientBrush resource gets its own instance.

Binding of DiscreteStringKeyFrame does not work

I have a Storyboard with StringAnimationUsingKeyFrames:
<Storyboard>
<StringAnimationUsingKeyFrames Storyboard.TargetProperty="(Button.ToolTip)" Storyboard.TargetName="xButton">
<DiscreteStringKeyFrame KeyTime="0" Value="{Binding State,Converter={StaticResource StateToStringConverter},StringFormat={x:Static props:Resources.xToolTipText}}"/>
</StringAnimationUsingKeyFrames>
....
<Storyboard>
xToolTipText comes from Resources:
Press ({0} State)
The value received for resources is variable State (int) from Model.
The whole thing can not work because binding of DiscreteStringKeyFrame does not work (I think the reason is that he does not belong to the visual tree).
Which is another way I can do this?
I used proxy binding as this post:
How to bind to data when the DataContext is not inherited
And it worked.

wpf dynamic change image source using timer

In WPF, I have 2 images, and I need to create a blinking effect (not using opacity).
Assume that I have a.png and b.png, first step showing a.png, after 0.5 seconds, it will show b.png, then after 0.5 seconds, it will show a.png, and repeat non-stop.
I've go through the forum, but I still have no luck to get example in vb, please help.
You may use an appropriate animation without any code behind:
<Window.Resources>
<BitmapImage x:Key="Image1" UriSource="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"/>
<BitmapImage x:Key="Image2" UriSource="C:\Users\Public\Pictures\Sample Pictures\Jellyfish.jpg"/>
</Window.Resources>
...
<Image x:Name="image" Source="{StaticResource Image1}">
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source"
Duration="0:0:1"
RepeatBehavior="Forever">
<DiscreteObjectKeyFrame Value="{StaticResource Image2}"
KeyTime="0:0:0.5"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
Perhaps replace the Loaded event by one that better suits your needs.
If you really want to do it in code behind, you may create a DispatcherTimer with an Interval set to half a second, and in the timer's Tick event handler alternately set the image's Source property to one of the two images.
I'm not fit in vb.net, but in c# you can do with something like
public ImageSource GetImageSourceFromImage(Bitmap pngFile)
{
MemoryStream imageStream = new MemoryStream();
pngFile.Save(imageStream, ImageFormat.Png);
imageStream.Seek(0, SeekOrigin.Begin);
return BitmapFrame.Create(imageStream);
}
This function gives you an imagesource which you can just assign to your image-object.

How can I share a VisualStateManager between two (or more) XAML files?

We're writing a Prism based Silverlight application and we've got a whole bunch of pages in separate modules.
The transition between the pages is handled via navigation events and each module has the following methods implemented to show the page when navigated to and hide it when navigated from:
public void Show()
{
VisualStateManager.GoToState(this, "ShowState", true);
}
public void Hide()
{
VisualStateManager.GoToState(this, "HideState", true);
}
At the moment "ShowState" and "HideState" are defined in each module's XAML file so are duplicated far too many times.
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStates">
<VisualState x:Name="ShowState">
...
</VisualState>
<VisualState x:Name="HideState">
...
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Where ... represents the Storyboard for each transition.
I've just spotted an error in the Storyboard definitions and at the moment I'm going to have to replicate the fix across all the files. It would be better if there was only one definition of the Storyboard which could be referenced in each file.
I've searched all morning for the right syntax but have had no luck what so ever.
How can I share this VisualStateManager between all our XAML files?
<Storyboard x:Key="ShowStoryboard">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<VisualState x:Name="ShowState">
<BeginStoryboard Storyboard="{StaticResource ShowStoryboard}"/>
</VisualState>
Referencing your Storyboard within XAML can be done as seen above. With the top most portion being a Storyboard stored as a Resource somewhere. After that you should be able to use the BeginStoryboard reference within your VisualState.
EDIT: The above appears possible within WPF however it is not possible in SL. As of current it does not appear the abilty to reuse a Storyboard or VisualState is possible in SL. You should still be able to achieve what you are trying to do by encapsulating the VisualStateManager behavior within a style applied to a custom control. This would provide you the single point of failure you are looking for.

How do I know if a drag/drop has been cancelled in WPF

I'm writing a user control in WPF which is based on a ListBox. One of the main pieces of functionality is the ability to reorder the list by dragging the items around. When a user drags an item I change the items Opacity to 50% and physically move the item in an ObservableCollection in my ViewModel depending on where the user wants it. On the drop event I change the Opacity back to 100%.
The problem I've got is that if the user drags the item off my control and drops it somewhere else then I need to change the Opacity back to 100% and move the item back to where it was when the user started the drag. Is there an event I can handle to capture this action? If not is there any other cunning way to solve this problem?
Assuming you are using the built-in drag and drop functionality, you can use the return value of the DoDragDrop method. If the drop target does not accept the dragged object, then DoDragDrop returns DragDropEffects.None.
This of course assumes that the other controls on your form do not allow the dropping of your list items.
I've done this using event triggers in XAML before. In my case, they were transparent (30% opacity) before and when the user drags over, the opacity is set to 100%.
<EventTrigger RoutedEvent="DragDrop.DragEnter">
<BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" x:Name="FadeInStoryboard_BeginStoryboard1"/>
</EventTrigger>
<EventTrigger RoutedEvent="DragDrop.DragLeave">
<BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" x:Name="FadeOutStoryboard_BeginStoryboard1"/>
</EventTrigger>
The storyboards would then animate the opacity
<Storyboard x:Key="FadeInStoryboard">
<DoubleAnimation To="1" Duration="0:00:00.2" Storyboard.TargetName="UserControl" Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
<Storyboard x:Key="FadeOutStoryboard">
<DoubleAnimation To="0.3" Duration="0:00:00.2" Storyboard.TargetName="UserControl" Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>

Resources