企业应用中,经常会遇到一些需要定时自动执行的程序来完成某些功能,比如:自动定时从第三方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:自动执行"机器人"程序若干注意事项的更多相关文章

  1. Windows自动执行应用程序或脚本(可以通过写bat文件定时关机等)

    1. Windows每天定时执行某个应用程序 1.1 右键我的电脑选择管理,并选择任务计划程序,如下 演示 --- 1.2 创建基本任务 演示 1.3 Windows每天定时关机设置参数 演示 1. ...

  2. SAS启动时自动执行代码

    有时候我们希望SAS启动时自动执行已经编写好的程序,可以按照以下方法实现: 首先正常打开SAS,编写我们想要让SAS启动时自动执行的代码,例如获取桌面文件夹路径,以便在其他程序中引用这个路径. pro ...

  3. 使用自定义脚本扩展程序自动执行 VM 自定义任务

     在 Build 开发者大会上推出VM 扩展程序的其中一个称为"自定义脚本扩展程序",它支持 PowerShell.如果这是您第一次访问这些博客,可能需要查看以前的博客,请单击 ...

  4. 如何让PHP程序自动执行(后台)

    如何让php程序自动执行,这个就需要用到一个函数了: int ignore_user_abort ( [bool setting] )  定义和用法 ignore_user_abort() 函数设置与 ...

  5. Testlink自动执行用例小程序

    记得原来在一个公司时,具体很多原因,testlink上项目中的用例都需要执行形成漂亮的报告,但实际测试中又不需要去执行,所以就必须将用例根据上一次测试报告一个一个手工去贴结果刷用例,几百条用例,几天就 ...

  6. WPF 开发自动开机启动程序

    原文:WPF 开发自动开机启动程序 本文告诉大家如何在 WPF 开发一个可以自动启动的程序 本文使用的自动开机启动方法是通过快捷方式放在启动文件夹的方式. 创建快捷方式 /// <summary ...

  7. JVM执行Java程序时内存的划分

    Java虚拟机在执行Java程序过程中会把它所管理的内存区域划分为若干个不同的数据区域. Java虚拟机所管理的内存包括以下几个运行时区域: 1.程序计数器(Program Couter Regist ...

  8. 使用php作linux自动执行脚本

    使用php作linux自动执行脚本 [来源] 达内    [编辑] 达内   [时间]2013-03-21 在作社区时, 时常需要统计上线人数等数据. 一般做法是, 把这段代码放在用户 login或者 ...

  9. Oracle DB 使用调度程序自动执行任务

    • 使用调度程序来简化管理任务 • 创建作业.程序和调度 • 监视作业执行 • 使用基于时间或基于事件的调度来执行调度程序作业 • 描述窗口.窗口组.作业类和使用者组的用途 • 使用电子邮件通知 • ...

随机推荐

  1. Linux- Nginx简单的负载均衡(一)

    这里先进行简单的nginx负载,安装nginx这里就不多说了,我们情景假设在已经安装好了nginx上: 1)查询nginx中的upstrea负载均衡模块  默认是有安装的.进入nginx源码目录中 . ...

  2. Java基础知识学习(七)

    线程(续) 线程同步 当两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被一个线程占用.达到此目的的过程叫做同步(synchronization) 可以用两种方法同步化代码.两者 ...

  3. 如何删除或重置spfile中的参数

    在ORACLE中,修改spfile中的参数一般非常容易,那么如何删除spfile中的参数呢? 下面我们用一个案例来介绍一下,如何删除spfile中的参数,一种方法就是创建对应的pfile,删除对应的参 ...

  4. 《Java JDK7 学习笔记》课后练习题2

    1.如果在hello.java中撰写以下的程序代码: public class Hello {     public static dmain(String[]args) {          Sys ...

  5. Oracle Data Provider for .NET

    官方地址: http://www.oracle.com/technetwork/topics/dotnet/index-085163.html 终于有正式版了.不用装客户端,又小,确实好.

  6. QT学习第2天

    回顾: 1.构建一个QT工程步骤 (1)qmake -project (2)qmake (3)make   2.两个常用的组件 QLabel 标签 QPushButton 按钮   --------- ...

  7. html之div拖拽,html5拖拽

    html之div拖拽 http://www.w3school.com.cn/html5/html_5_draganddrop.asp

  8. android apk 防止反编译技术第四篇-对抗JD-GUI

    又到周末一个人侘在家里无事可干,这就是程序员的悲哀啊.好了我们利用周末的时间继续介绍android apk防止反编译技术的另一种方法.前三篇我们讲了加壳技术(http://my.oschina.net ...

  9. 150923-碎觉要-PHP,Linux

    今天懒懒的,还是每天都懒懒的. 早上下午都没有更.还好还有晚上更的想法和行动. 总结如下 1.PHP --wamp的一点配置问题,把根文件改为自己所要的文件夹.改动Apache的配置文件以及更改wam ...

  10. windows 7 语言切换 Vistalizator

    Try Vistalizator - this tool allows you to change display language in Windows editions other than (o ...