Làm Window Assistant bằng WPF

Window Assistant

Khái niệm hay Cái mẹ gì thế.

image

Ừ thì bắt chước touch assistant ios thôi nhưng mà là cho các ứng dụng window.
Nó cung cấp các notification của main window và các quick access.
Nó có thể kéo tới vị trí thuận tiện và khi click vào nó mở lại main window

Mục đích hay Để làm cái quái gì

Trong công việc chúng ta thường mở rát nhiều ứng dụng và không dễ để quản lý chúng. Assistant giúp bạn tập trung hơn vào ứng dụng của nó cũng như cung cấp một lối tắt đến ứng dụng của bạn.

Có task bar rồi mà?

Ờ thì đôi khi có những ứng dụng chạy task rất lâu như automation test. Trong lúc đó ta muốn ẩn đi để làm task mới và khi hoàn thiện assistant sẽ thông báo cho ta.

Tạo quách notification đi.

Ờ thì, cho màu mè. Rảnh làm chơi vậy.

Framework hay Dùng cái gì bây giờ.

WPF. chắc chẳng cần giới thiệu.

Bắt đầu thôi hay Chiến mẹ mày đi

  1. Tạo 1 WPF project mới. Trong đó mặc định có cái MainWindow.xaml và MainWindow.cs rồi.
  2. Thêm 1 window vào project đặt tên là WindowAssistant
  3. Lúc này có 2 file WindowAssistant.xaml và WindowAssistant.cs
  4. Sửa lại file WindowAssistant.xaml chút xíu
<Window x:Class="FloatAssistant.WindowAssistant"
        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:FloatAssistant"
        mc:Ignorable="d"
        Title="WindowAssistant"
        WindowStyle="None" 
        Background="Transparent"
        AllowsTransparency="True" 
        BorderThickness="0"
        Height="50" Width="50"
        WindowStartupLocation="CenterScreen"
        ShowInTaskbar="False"
        Topmost="True">
    <Grid >
        <Border CornerRadius="10" Background="#8000" 
            Height="50" VerticalAlignment="Center"
            MouseLeftButtonDown="Grid_MouseLeftButtonDown">
            <Grid>
                <Ellipse Fill="#4888" Margin="5"/>
                <Ellipse Stroke="#2000" StrokeThickness="1" 
                     Fill="#8888" Margin="8"/>
                <Ellipse Stroke="#2000" StrokeThickness="1"
                    Fill="#8fff" Margin="11"/>
            </Grid>
        </Border>
        </Grid>
    </Grid>
</Window>

Trong đó : Background="Transparent" set background. Nhưng background chỉ trong suốt khi AllowsTransparency="True". ShowInTaskbar="False" để ẩn icon ở taskbar, Topmost="True" để assistant luôn trên top, WindowStyle="None" loại bỏ title của window và các button state như minimize, maximize và close.

Border là nền màu đen và các vòng ellipse tạo các vòng tròn đồng tâm trên giao diện assistant. Với mục đích trang trí, nên bạn có thể thay bằng bất kỳ UIControl nào.
Event MouseLeftButtonDown="Grid_MouseLeftButtonDown" được implement trong file .cs để thực hiện click và drag.

  1. Trong file WindowAssistant.cs thêm 1 delegate để liên kết với các control khác.
public EventHandler Clicked;
  1. Update Event MouseLeftButtonDown như sau:
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove();
    if (Left == 0 || Left == SystemParameters.PrimaryScreenWidth - Width)
    {
        Clicked?.Invoke(sender, e); 
        // Assistant luôn nằm trong 1 cạnh của screen
        // Trong trường hợp Assistant không dịch chuyển 
        // Event Clicked sẽ được gọi
        // Điều kiện có thể thay đổi đê chính xác hơn
    }
    else
    {
        MoveToEdge();
        // ngược lại với trường hợp trên 
        // thì luôn di chuyển về 1 trong 2 cạnh màn hình
    }
}

public void MoveToEdge()
{
    Point centerPoint = new Point(Left + Width / 2, Top + Height / 2);
    double destination = 0;
    if (centerPoint.X > SystemParameters.PrimaryScreenWidth/2)
    {
        destination = SystemParameters.PrimaryScreenWidth - Width; 
        // Trong trường hợp assistant bị kéo lệch sang bên phải thì move sang cạnh phải
    }
    // ngược lại, move sang cạnh trái.

    TimeSpan timeOfAnimation = TimeSpan.FromMilliseconds(200 + Math.Abs(destination - Left));
    // Thời gian phụ thuộc vào khoảng cách với cạnh màn hình
    DoubleAnimation moveToEdge = new DoubleAnimation()
    {
        From = Left,
        To = destination,
        Duration = new Duration(timeOfAnimation),
        FillBehavior = FillBehavior.Stop,
        EasingFunction = new QuarticEase()
        {
            EasingMode = EasingMode.EaseOut
            // Thêm easing function cho chân thật
        }
    };
    BeginAnimation(LeftProperty, moveToEdge);
    // Đây là cách đơn giản nhất để begin animation
}

Method MoveToEdge được expose vì khi khởi tạo tại window khác và show lên, nó sẽ được gọi để di chuyển về phía 1 cạnh.

  1. Khai báo trong MainWindow.
// Khai báo trong Constructor của Mainwindow hoặc event Window_Loaded 
WindowAssistant = new WindowAssistant();
WindowAssistant.Clicked += WindowAssistant_Click;

// Khi event Clicked được gọi. Assistant sẽ ẩn đi và MainWindows hiện thị trở lại
private void WindowAssistant_Click(object sender, EventArgs e)
{
    ShowInTaskbar = true;
    WindowState = WindowState.Normal;
    WindowAssistant.Hide();
    Show();
    Focus();
}
  1. Gọi khi minimize MainWindow
// Cần khai báo event StateChanged ở file MainWindow.xaml
private void Window_StateChanged(object sender, EventArgs e)
{
    if(WindowState == WindowState.Minimized)
    {
        WindowAssistant.Left = Left + Width / 2;
        WindowAssistant.Top = Top + Height / 2; 
        // WindowAssistant hiện thị tại giữa main window 
        WindowAssistant.Show();
        // Và di chuyển về một cạnh màn hình.
        WindowAssistant.MoveToEdge();
        // Ẩn icon ở taskbar đi cho huyền bí
        ShowInTaskbar = false;
    }
}

Lưu ý nhỏ hay Coi chừng đấy

Method DragMove() trong bước 6 cho phép kéo window đi theo chuột. Đây là method mặc định của Window class. Nó hoạt động đồng bộ, tức là khi nào chú mày thôi drag nó mới ra khỏi event đó để thực hiện lệnh tiếp theo. Điều đó có nghĩa là các lệnh theo sau nó sẽ thực hiện khi mouse up.
Tuy nhiên, event mouse up sẽ bị degraded. Vì thế đừng cố đưa các lệnh sau DragMove vào event MouseUp làm gì rồi lại hỏi tại sao.

Tạm kết hay Vậy thôi à

Chẳng muốn bàn luận về WPF ở đây. Anh em nào muốn tìm hiểu mà ngại đọc tiếng Anh, chúng ta sẽ cùng bàn luận sau. Chẳng qua chỉ muốn chia sẻ ý tưởng không giống ai và không giống giáo trình.
À quên còn cái message với quick access qua các button nữa. Để sau nhé.

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?