Easy start guide for WPF and New Start Guide for wpf
These two days are not busy, so I made a simple new beginner guide Demo. Because it is not a project application, it is very rough, that is, to give the people who need it a thought.
The new user guide function tells the user the operation sequence on the page, the first step, the second step, and so on, and finally closes the New User Guide page.
In my habits, let's show you the effect first.
The display of results is very simple, that is, to tell the user to operate the control to make a prompt.
To achieve this function, the idea is probably the following:
1. Mask form
Mask the main form, translucent effect, commonly used as a mask, usually set a background color, and then set the transparency, similar to this blog article
First set a transparent form
<Window x:Class="SimpleGuide.GuideWin" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SimpleGuide" mc:Ignorable="d" Title="GuideWin" WindowStyle="None" AllowsTransparency="True" x:Name="gw" Background="#01FFFFFF" ShowInTaskbar="False"> <Grid> <Border x:Name="bor" BorderBrush="White" BorderThickness="2" CornerRadius="5" Opacity="0.8"> <Border.Effect> <DropShadowEffect ShadowDepth="0" Color="#FF414141" BlurRadius="8" /> </Border.Effect> <Border Background="Black" Opacity="0.5" Margin="0" CornerRadius="5" /> </Border> <Canvas x:Name="can"></Canvas> </Grid></Window>
From the XAML code, we can see that the Background attribute does not use the header "Transparent" but uses "# 01FFFFFF", because if Transparent is used, it is Transparent, you can directly click the control in the main form. This is what we don't want, so we set "# 01FFFFFF", a almost transparent color.
2. display the control to be operated
To guide a widget, We Need To enclose it first. The primary task of the widget is to obtain the coordinates of the widget in the current form.
Point point = fe.TransformToAncestor(Window.GetWindow(fe)).Transform(new Point(0, 0));
After obtaining the coordinates, You need to enclose the control. My method is to take the current coordinates-5, width and height + 10 to draw a blank area. In fact, this part should be erased
RectangleGeometry rg1 = new RectangleGeometry();rg1.Rect = new Rect(point.X - 5, point.Y - 5, fe.ActualWidth + 10, fe.ActualHeight + 10);borGeometry = Geometry.Combine(borGeometry, rg1, GeometryCombineMode.Exclude, null);
3. Draw a guideline for UC
It is easy to design and guide UC. It looks quite simple.
It is to use Path to draw a range, but the initial idea of the dotted box is to use Line, but it is too time consuming to use the StrokeDashArray attribute, stroke is the border line of the Path itself. Of course, it is really a border, so it is difficult to set Margin or Padding. Therefore, the final practice is to draw another area in the outer layer, this area does not contain borders, and the fill color is the same.
<Path Fill="#FF2FBEED"> <Path.Data> <GeometryGroup> <PathGeometry Figures="M 8,22 A 12,12 0 1 1 22,8 L 102 8 L 102 62 L 8 62 Z" /> </GeometryGroup> </Path.Data></Path><Path StrokeThickness="1" Stroke="White" StrokeDashArray="2,1" Fill="#FF2FBEED"> <Path.Data> <GeometryGroup> <PathGeometry Figures="M 10,20 A 10,10 0 1 1 20,10 L 100 10 L 100 60 L 10 60 Z" /> </GeometryGroup> </Path.Data></Path>
The display content is a Textblock. At that time, a problem was encountered, that is, the line feed problem. Textblock must have a Width to wrap the line. However, because the outermost layer is Viewbox, I tried to get the Width or ActualWidth of UC, but none of them would work. Therefore, the final solution is to input the Width and height of a form, instead of setting the Width and height of UC externally.
public HintUC(string xh, string content, Visibility vis = Visibility.Visible, int width = 260, int height = 160){ InitializeComponent(); this.Width = width; this.Height = height; this.tb_nr.Width = width / 4; this.tb_xh.Text = xh; this.tb_nr.Text = content; this.btn_next.Visibility = vis;}4. Next Step
Triggering the next step is equivalent to the sub-Control calling the main control event. In this case, it is to write a delegate to implement the specific method in the main form.
Private void show (int xh, FrameworkElement fe, string con, Visibility vis = Visibility. visible) {Point point = fe. transformToAncestor (Window. getWindow (fe )). transform (new Point (0, 0); // obtain the control coordinate Point RectangleGeometry rg = new RectangleGeometry (); rg. rect = new Rect (0, 0, this. width, this. height); borGeometry = Geometry. combine (borGeometry, rg, GeometryCombineMode. union, null); bor. clip = borGeometry; RectangleGeometry Rg = new RectangleGeometry (); rg1.Rect = new Rect (point. x-5, point. y-5, fe. actualWidth + 10, fe. actualHeight + 10); borGeometry = Geometry. combine (borGeometry, fig, GeometryCombineMode. exclude, null); bor. clip = borGeometry; HintUC hit = new HintUC (xh. toString (), con, vis); Canvas. setLeft (hit, point. X + fe. actualWidth + 3); Canvas. setTop (hit, point. Y + fe. actualHeight + 3); hit. nextHintEvent-= Hit_nextHintEvent; hit. nextHintEvent + = Hit_nextHintEvent; can. children. add (hit); index ++ ;}
private void Hit_nextHintEvent(){ if (list[index - 1] != null) { can.Children.Clear(); } if (index == list.Count - 1) show(index + 1, list[index].Uc, list[index].Content, Visibility.Collapsed); else show(index + 1, list[index].Uc, list[index].Content);}
We need to declare an index variable externally to record the index of the current List set. First, we need to determine whether the current content is not empty. If so, to clear it, if it is not cleared, a bunch of prompt boxes will be displayed, and then you can determine whether it is the last control in the List set. If yes, the "Next" button is no longer displayed ".
5. Extensions
Because it is a small Demo, some problems have been found, but it has not been solved. For example, if the main form is not borderless, there will be problems in value locating.
This is because the pop-up guide form obtains the size of the main form, but when the Point is used to obtain the Coordinate Position of the control, the main form does not contain the header. Because the mask does not have a header, the positioning error occurs, I have not found a good solution yet. If you know how to solve this problem, please kindly advise. Thank you.
Display the guiding content. You can also change it to a Grid. In this way, you can pass in UserControl. If you are interested, you can modify it yourself.
Source code: Demo