WPF:自动执行"机器人"程序若干注意事项-阿里云开发者社区

开发者社区> 杨俊明> 正文

WPF:自动执行"机器人"程序若干注意事项

简介: 企业应用中,经常会遇到一些需要定时自动执行的程序来完成某些功能,比如:自动定时从第三方web service取回数据、定时对历史数据进行清理、定时向ftp上传业务数据...这类程序,我习惯称为“机器人”程序,就象机器一样机械、高效、重复的执行某些任务。
+关注继续查看

企业应用中,经常会遇到一些需要定时自动执行的程序来完成某些功能,比如:自动定时从第三方web service取回数据、定时对历史数据进行清理、定时向ftp上传业务数据...

这类程序,我习惯称为“机器人”程序,就象机器一样机械、高效、重复的执行某些任务。通常部署上线后,都是放在服务器上一直开着,不允许轻易被关闭,而且最好要有一个界面,随时可以手动方便控制状态或查看运行情况,一旦发生异常情况,能及时通知管理员(Email或短信之类)
如果是采用WPF技术开发,以下是几个需要注意的地方:

1、无边框窗体(防止用户不小心点到 右上角的关闭按钮)

<Window x:Class="WeatherSpider.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         WindowStyle="None" ...>

将主窗体的WindowStyle设置成None即可

2、无边框窗体的移动
去掉顶上的边框后,通常为了美观,我们需要自己在顶上放一个伪造的标题栏,类似下面这样

<Border Grid.Row="0" MouseLeftButtonDown="TitleBarOnMouseLeftButtonDown" >
    <Grid Margin="5,5,5,0" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Foreground="GreenYellow" FontSize="16" x:Name="tbTitle">全国机场天气-采集机器人</TextBlock>
        <TextBlock Text="最小化" Grid.Column="1" Foreground="GreenYellow" FontSize="12" VerticalAlignment="Center" TextAlignment="Right" x:Name="btnMin" Cursor="Hand" MouseLeftButtonDown="btnMin_MouseLeftButtonDown"></TextBlock>
    </Grid>
</Border>

为了实现鼠标拖动标题栏时,窗体也能跟着拖动,需要在标题栏的对象上增加MouseLeftButtonDown事件处理(即:上面代码Border上的MouseLeftButtonDown="TitleBarOnMouseLeftButtonDown" )

private void TitleBarOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    base.DragMove();
}

哦,原来 so easy !

3.最小化到系统托盘
Winform中的NotifyIcon控件在WPF中仍然可以继续使用
先 using System.Windows.Forms; 添加Windows.Forms命名空间的引用
再声明一个窗体级的变量

private readonly NotifyIcon notifyIcon;

最后在主窗体的构架函数中,加入下列这一段

notifyIcon = new NotifyIcon();
notifyIcon.BalloonTipText = Properties.Resources.AppTitle + " 正在运行!";
notifyIcon.Text = Properties.Resources.AppTitle;//指定托盘提示文字为资源中的AppTitle字符串
notifyIcon.Icon = Properties.Resources.App;//指定托盘图标为资源中的"App"图标
notifyIcon.Visible = false;
notifyIcon.MouseClick += notifyIcon_MouseClick;

//托盘右键菜单
MenuItem itemShowMainForm = new MenuItem("显示主界面");
itemShowMainForm.Click += ShowMainWindow;
MenuItem itemExit = new MenuItem("退出");
itemExit.Click += ExitApplication;
MenuItem[] menuItems = new[] { itemShowMainForm, itemExit };
notifyIcon.ContextMenu = new ContextMenu(menuItems);

notifyIcon_MouseClick事件代码如下:

public void Show() {
    Visibility = Visibility.Visible;
    Activate();
    notifyIcon.Visible = false;
}

 /// <summary>
 /// 托盘图标鼠标点击处理
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
void notifyIcon_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        if (Visibility == Visibility.Visible)
        {
            Visibility = Visibility.Hidden;
            notifyIcon.Visible = true;
        }
        else
        {
            Show();
        }
    }
}

//显示主界面
void ShowMainWindow(object sender, EventArgs e)
{
    Show();
}

在上面提到的第2点中,可能已经有朋友注意到了“最小化”的文本上,已经加了 MouseLeftButtonDown="btnMin_MouseLeftButtonDown"事件处理,即点击“最小化”这几个字,可以缩小到托盘区,代码如下:

private void btnMin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Visibility = Visibility.Hidden;//隐藏主窗体
    notifyIcon.Visible = true;//显示托盘图标
    notifyIcon.ShowBalloonTip(1000);//显示托盘图标上的气泡提示1秒钟
}


4.程序退出时,主动提醒
虽然做了无边框窗体的处理,但是如果用户意外按了Alt+F4,甚至误操作注销或重启Windows,程序还是会直接退出的,最好能给个提示,这样管理员看到提示后,有机会取消误操作
先给主窗体增加Closing事件处理,主窗体构造函数中,加入下面这一行

Closing += Window_Closing;

Window_Closing事件如下:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    if (MessageBox.Show("确定要退出[" + Properties.Resources.AppTitle + "]吗?",
                                      Properties.Resources.AppTitle,
                                      MessageBoxButton.YesNo,
                                      MessageBoxImage.Question,
                                      MessageBoxResult.No) == MessageBoxResult.Yes)
    {                
        this.Closing -= Window_Closing;//注意:这里要注销事件监听,否则会连续弹出二次提示框才能退出
        notifyIcon.Visible = false;
        e.Cancel = false;
    }
    else
    {
        e.Cancel = true;
    }
}

经过上述处理后,用户按Alt+F4时,就会提示是否退出。但这样还不够,如果Windows注销时,仍然会直接退出
这就需要 using Microsoft.Win32;使用Win32命名空间下的某些功能了,主窗体构造函数中,增加:

//捕获关机事件
SystemEvents.SessionEnding += SystemEvents_SessionEnding;

处理代码如下:

void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{

    if (MessageBox.Show("[" + Properties.Resources.AppTitle + "]正在运行中,确定要退出吗?",
                          Properties.Resources.AppTitle,
                          MessageBoxButton.YesNo,
                          MessageBoxImage.Question,
                          MessageBoxResult.No) == MessageBoxResult.Yes)
    {
        e.Cancel = false;                
    }
    else {
        e.Cancel = true;
    }   
}

同时在刚才的Window_Closing中,增加一行代码:(见下面的注释行)

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    if (MessageBox.Show("确定要退出[" + Properties.Resources.AppTitle + "]吗?",
                                      Properties.Resources.AppTitle,
                                      MessageBoxButton.YesNo,
                                      MessageBoxImage.Question,
                                      MessageBoxResult.No) == MessageBoxResult.Yes)
    {
        SystemEvents.SessionEnding -= SystemEvents_SessionEnding; //取消关机事件监听
        this.Closing -= Window_Closing;
        notifyIcon.Visible = false;
        e.Cancel = false;
    }
    else
    {
        e.Cancel = true;
    }
}


5.单实例运行
Winform中要实现单实例运行,非常容易(见 利用c#制作托盘程序,并禁止多个应用实例运行),但是WPF中就有点麻烦,网上搜索了一下,有朋友已经解决了这个问题
引用using Microsoft.VisualBasic.ApplicationServices; (注:必须先添加对Microsoft.VisualBasic的程序集引用)
然后把App.xaml编译属性改成Page,同时修改App.xaml.cs代码如下:

using System.Windows;
using System.Diagnostics;
using System;
using WeatherSpider.Helper;

namespace WeatherSpider
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [STAThread]
        [DebuggerNonUserCode]        
        public static void Main(string[] a)
        {
            SingleApp app = new SingleApp();//SingleApp类后面马上会提到
            app.Run(a);
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            MainWindow w = new MainWindow();
            w.Show();//即调用主窗体中的Show方法,显示主窗体
        }

        public void Activate()
        {
            (MainWindow as MainWindow).Show();        
        }
     }
}

再创建一个SingleApp类

using Microsoft.VisualBasic.ApplicationServices;

namespace WeatherSpider.Helper
{
    public class SingleApp : WindowsFormsApplicationBase
    {
        App a;

        public SingleApp()
        {
            this.IsSingleInstance = true;
        }
        
        protected override bool OnStartup(StartupEventArgs eventArgs)
        {
            a = new App();           
            a.Run();
            return false;
        }
        
        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
        {
            base.OnStartupNextInstance(eventArgs);
            a.Activate();//第二个实例试图“启动”时,自动把已经运行的实例激活并显示
        }
    }

}

最后上图二张:

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
WPF TextBox自动滚动到最户一行
原文:WPF TextBox自动滚动到最户一行 textBox经常用来显示程序的运行状态或者消息,如何让他自动滚动呢? 在显示消息代码下加一条自动滚动到底部的语句即可:  TextBox1.ScrollToEnd(); (如果要显示垂直滚动条设置VerticalScrollBarVisibility="Auto",如果不显示设置为Hidden) 我用的程序代码如下:   this.
1265 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10095 0
阿里云RPA(机器人流程自动化)干货系列之二:认识RPA(下)
导读:本文是阿里云RPA(机器人流程自动化)干货系列之二,主要介绍了RPA的发展齐纳经和主要使用场景有哪些,目前国内外主流的RPA厂商以及RPA的未来在哪。 一、RPA的发展前景 根据Gartner的最新研究,2018年全球机器人流程自动化(RPA)软件的开支预计将达到6.8亿美元,同比增长57%,到2022年支出达到24亿美元。
8215 0
阿里云RPA(机器人流程自动化)干货系列之一:认识RPA(上)
导读:本文是阿里云RPA(机器人流程自动化)干货系列的开山之作,全面、详细的剖析了RPA的基本概念、给企业带来的价值点以及RPA的优劣势分析。 一、什么是RPA? 人类社会进入21世纪的第一个十年之后,全球企业大都面临着两个严峻的挑战:一是人力成本的不断飙升带来了企业经营成本的不断增加;二是业务的快速发展导致企业内部流程纷繁复杂,工作效率的提升跟不上业务的发展速度。
15887 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13893 0
《制造业中的机器人、自动化和系统集成》—— 1.3 机器人的演变
捷克斯洛伐克作家卡雷尔·恰佩克(Karel Capek)在他的科幻剧本《Rossum’s Universal Robots》(罗素姆万能机器人)中首次使用了“机器人”这个词。它根据捷克文Robota演变而来,原意为“劳役、苦工”。
1296 0
+关注
杨俊明
菩提树下的杨过 http://yjmyzz.cnblogs.com/
1105
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载