How do I “pause” a program to show user feedback?

When a user launches my program for the first time, I want them to go through a series of tips. Each time they click on a specific “breakpoint”, the program pauses what it does, the background will be a little fuzzy (except for the window area that the tooltip refers to), and the tooltip will appear at the top explaining how to use it / what to do and etc.

I don’t know what to call it, “learning tips” are called in my head, but in googling everything related to this shows loading common tutorials with WPF / C #.

What would be the best way to do this? Am I really just looking at using pop-ups and controls when they are visible? Is there a better / more elegant solution or any resources out there to help with this?

+4
source share
2 answers

Ok, I think I could devote too much time to it, but it sounded like a cool task: P

I created a Decorator class called TipFocusDecorator that handles all this.

 public class TipFocusDecorator : Decorator { public bool IsOpen { get { return (bool)GetValue(IsOpenProperty); } set { SetValue(IsOpenProperty, value); } } // Using a DependencyProperty as the backing store for Open. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(TipFocusDecorator), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsOpenPropertyChanged)); public string TipText { get { return (string)GetValue(TipTextProperty); } set { SetValue(TipTextProperty, value); } } // Using a DependencyProperty as the backing store for TipText. This enables animation, styling, binding, etc... public static readonly DependencyProperty TipTextProperty = DependencyProperty.Register("TipText", typeof(string), typeof(TipFocusDecorator), new UIPropertyMetadata(string.Empty)); public bool HasBeenShown { get { return (bool)GetValue(HasBeenShownProperty); } set { SetValue(HasBeenShownProperty, value); } } // Using a DependencyProperty as the backing store for HasBeenShown. This enables animation, styling, binding, etc... public static readonly DependencyProperty HasBeenShownProperty = DependencyProperty.Register("HasBeenShown", typeof(bool), typeof(TipFocusDecorator), new UIPropertyMetadata(false)); private static void IsOpenPropertyChanged(object sender, DependencyPropertyChangedEventArgs e) { var decorator = sender as TipFocusDecorator; if ((bool)e.NewValue) { if (!decorator.HasBeenShown) decorator.HasBeenShown = true; decorator.Open(); } if (!(bool)e.NewValue) { decorator.Close(); } } TipFocusAdorner adorner; protected void Open() { adorner = new TipFocusAdorner(this.Child); var adornerLayer = AdornerLayer.GetAdornerLayer(this.Child); adornerLayer.Add(adorner); MessageBox.Show(TipText); // Change for your custom tip Window IsOpen = false; } protected void Close() { var adornerLayer = AdornerLayer.GetAdornerLayer(this.Child); adornerLayer.Remove(adorner); adorner = null; } } 

This decorator should be used in XAML around the control you want to focus on. It has three properties: IsOpen , TipText and HasBeenShown . IsOpen must be set to true to display the focus and tip window (and automatically set to false when the prompt window is closed). TipText allows you to specify the text that should be displayed in the tooltip window. And HasBeenShown keeps track of whether the tooltip has been shown, so it only appears once. You can use Bindings for all of these properties or set them from code.

To create a focus effect, this class uses another custom Adorner, TipFocusAdorner :

 public class TipFocusAdorner : Adorner { public TipFocusAdorner(UIElement adornedElement) : base(adornedElement) { } protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) { base.OnRender(drawingContext); var root = Window.GetWindow(this); var adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement); var presentationSource = PresentationSource.FromVisual(adornerLayer); Matrix transformToDevice = presentationSource.CompositionTarget.TransformToDevice; var sizeInPixels = transformToDevice.Transform((Vector)adornerLayer.RenderSize); RenderTargetBitmap rtb = new RenderTargetBitmap((int)(sizeInPixels.X), (int)(sizeInPixels.Y), 96, 96, PixelFormats.Default); var oldEffect = root.Effect; var oldVisibility = AdornedElement.Visibility; root.Effect = new BlurEffect(); AdornedElement.SetCurrentValue(FrameworkElement.VisibilityProperty, Visibility.Hidden); rtb.Render(root); AdornedElement.SetCurrentValue(FrameworkElement.VisibilityProperty, oldVisibility); root.Effect = oldEffect; drawingContext.DrawImage(rtb, adornerLayer.TransformToVisual(AdornedElement).TransformBounds(new Rect(adornerLayer.RenderSize))); drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(22, 0, 0, 0)), null, adornerLayer.TransformToVisual(AdornedElement).TransformBounds(new Rect(adornerLayer.RenderSize))); drawingContext.DrawRectangle(new VisualBrush(AdornedElement) { AlignmentX = AlignmentX.Left, TileMode = TileMode.None, Stretch = Stretch.None }, null, AdornedElement.RenderTransform.TransformBounds(new Rect(AdornedElement.RenderSize))); } } 

This dims and blurs (and freezes because it actually uses screen capture) the entire window, keeping the desired controls focused and clear (and moving - that is, in TextBoxes, the text input carriage will still be visible and blinking).

To use this Decorator, you must install it the same way in XAML:

 <StackPanel> <local:TipFocusDecorator x:Name="LoginDecorator" TipText="Enter your username and password and click 'Login'" IsOpen="{Binding ShowLoginTip}"> <local:LoginForm /> </local:TipFocusDecorator> </StackPanel> 

And the end result when ShowLoginTip set to true :

enter image description here

KNOWN ISSUES

Currently, a simple MessageBox used to display the tooltip, but you can create your own Window class for tooltips, label it whatever you want, and call it ShowDialog() instead of MessageBox.Show() (and you can also control where Window appears if you you want it to appear right next to the focused control or something like that).

Also, this will not work in UserControls right away because AdornerLayer.GetAdornerLayer(AdornedElement) will return null inside UserControls. This could be easily AdornerLayer looking for the AdornerLayer UserControl (or parent of the parent, recursively). There are functions for this.

This will not work for pages, but only for Windows. Just because I use Window.GetWindow(this) to get the parent Window Decorator ... You can use other functions to get a parent that could work either on Windows, or on pages, or whatever. As with the AdornerLayer problem, there are many solutions to this.

In addition, I assume that this can be animated in some way (for example, the blur and dimming effect appears, for example), but did not really look at it ...

+6
source

You can create your advice in the form of a window and show it with ShowDialog() . This gives you a Modal dialog like the others. Be sure to set it as the owner. Before you show it, you can use

 <UIElement.Effect> <BlurEffect/> </UIelement.Effect> 

to set the blur effect of a window or an external container (mesh). The radius property sets the “level” of blur, so I assume that you can first set it to 0 and change it programmatically when you show the dialog

0
source

All Articles