热烈祝贺台州朗动科技的站长论坛隆重上线!(2012-05-28)    热烈庆祝伟大的祖国60周年生日 点击进来我们一起为她祝福吧(2009-09-26)    站长论坛禁止发布广告,一经发现立即删除。谢谢各位合作!.(2009-08-08)    热烈祝贺台州网址导航全面升级,全新版本上线!希望各位一如既往地支持台州网址导航的发展.(2009-03-28)    台州站长论坛恭祝各位新年快乐,牛年行大运!(2009-01-24)    台州Link正式更名为台州网址导航,专业做以台州网址为主的网址导航!(2008-05-23)    热烈祝贺台州Link资讯改名为中国站长资讯!希望在以后日子里得到大家的大力支持和帮助!(2008-04-10)    热烈祝贺台州Link论坛改名为台州站长论坛!希望大家继续支持和鼓励!(2008-04-10)    台州站长论坛原[社会琐碎]版块更名为[生活百科]版块!(2007-09-05)    特此通知:新台州站长论坛的数据信息全部升级成功!">特此通知:新台州站长论坛的数据信息全部升级成功!(2007-09-01)    台州站长论坛对未通过验证的会员进行合理的清除,请您谅解(2007-08-30)    台州网址导航|上网导航诚邀世界各地的网站友情链接和友谊联盟,共同引领网站导航、前进!(2007-08-30)    禁止发广告之类的帖,已发现立即删除!(2007-08-30)    希望各位上传与下载有用资源和最新信息(2007-08-30)    热烈祝贺台州站长论坛全面升级成功,全新上线!(2007-08-30)    
便民网址导航,轻松网上冲浪。
台州维博网络专业开发网站门户平台系统
您当前的位置: 首页 » ASP/ASP.NET编程 » WinForm程序中使用控制台作为输出窗口

WinForm程序中使用控制台作为输出窗口

论坛链接
  • WinForm程序中使用控制台作为输出窗口
  • 发布时间:2009-07-31 13:15:48    浏览数:7518    发布者:tznktg    设置字体【   
Lambda表达比代表定义和带外方法定义的结合更清楚,且相关的额外工作只需要满足语言定义即可。不过,它也有一些不足之处。如果某个方法的参数包含System.Delegate 这样的抽象类型,用lambda表达式介绍特殊的问题:C#编译器不能将lambda表达式转换成还未明确定义的衍生代表类型。

如果不仔细思考一下,你的代码看上去就会像是来自.NET1.0的东西。在本文中,我将告诉告诉你为什么lambda表达式不足以被直接转换成抽象代表类型,并且教你怎样使得编译器转换你所定义的指定代表。解决方案依赖于Windows Presentation Foundation(WPF)和System.Windows.Threading.Dispatcher组件,但是严格意义上说,该问题不是一个WPF问题。文中所描述的问题出现在若干.NET框架中,包括Windows Forms,Office 应用程序接口和映射应用程序接口。你可以按照下列方法来处理同类问题。

无论我什么时候使用.NET框架中带有来自代表表格的参数的应用程序接口,我都会倾向于使用lambda表达式而不是更详细的表达式。例如,这行代码创建了一个System.Windows.Threading.Timer,在计时器失效时,该代码调用了一个TickHandler方法:


tick = new System.Threading.Timer((unused) =>
TickHandler());


如果方法的内容足够少,我就会用方法的内容替代TickHandler()方法调用。该方法大多数情况下都有效,但是当应用程序接口将System.Delegate作为参数时,这一技巧不管用。例如,我们将System.Windows.Controls.Dispatcher.Invoke()方法穿过WPF中的线程实施调用:


public object Invoke(
delegate method,
params object[] args)


现在考虑一下当我们尝试用lambda表达式来执行这样的调用时,将会发生什么:

以下为引用的内容:

MyTime.Dispatcher.Invoke(() => DoSomething());


会出现隐秘错误:


error CS1660: Cannot convert lambda expression to


type 'System.Delegate' because it is not a delegate type



或许第一次看到这个错误的时候,你还不知道到底是怎么一回事。当然,这的确是一个代表类型。编译器不像人一样的灵活。System.Delegate类型是一个抽象类型,且该类型的推理工具不能推断出自变量或某些用于未知代表类型的返回值的数量和种类。要解决这一问题,我们必须创建一个具体的代表类型并为该类型指定lambda表达式。记住,代表类型要求你将方法视为数据。

我创建了一个WPF计时器程序来展示其工作原理,其中阐述了C#3.0 怎样简化与老式应用程序接口(下图)的运行。



当你做演示的时候,该示例中的应用程序运行了一个计时器,随着设定时间流逝,它的颜色会从绿色转为黄色再转为红色。这是一个很好的演示跨线程调用的方法,因为该计时器在背景线程中运行。

按照时间的改变来更新演示要求对出自计时器的事件作出响应。计时器在背景线程中运行,所以你会很轻易地犯我们在前面提到过的错误。

更新应用程序

用户界面处理的是简单代码。当计时器失效时它会生效,而且代码会更新计时器的显示。这一更新必须改变文本,或控制背景。如下所示:


MyTime.Background = newBrush;
MyTime.Content = label


计时器在背景线程上运行,所以你需要通过使用Dispatcher.Invoke()边界线执行调用。这两行代码是你想列入lambda表达式的代码,不是证明方法定义的逻辑理由。但是我之前就讲过lambda不会与Didpatcher.Invoke一起运行,除非是你使用了具体的代表定义才行。这之中的一部分已经在.NET框架3.5中定义了。
      我们可以使用嵌入式代表定义并对它们进行分配,这些都是的该解决方案比起先前提到过的案例都要省事一些。这两行代码也要求一对参数:一个用于文本的字符串和用于背景颜色的颜色刷。这意味着你需要使用的代表定义要考虑到这两个参数并返回无效值:

Action updateTimer;

在声明变量后,你可以为代码指定需要执行的代表变量。这里你可以使用lambda表达式,因为Action是一个具体的代表定义:

updateTimer = (label, newBrush) =>
{
MyTime.Background = newBrush;
MyTime.Content = label;
};


现在,当计时器提出事件时,你已经拥有了一些需要执行的指向该代码的变量。接下来要做的就只是通过Dispatcher.Invoke()使用代表定义:

if (!MyTime.Dispatcher.CheckAccess())
{
MyTime.Dispatcher.Invoke(updateTimer,
newLabel, next);
}
else
updateTimer(newLabel, next);


这一过程十分简单,但是却要求你反复进行,因此,我们可以让步骤变得容易一点。

这里其实由一个简单的模式。事件处理器可以从背景线程中调用出来。当我们使用计时器,或者异步调用Web服务以及其他类似任务的时候,你就会看到这一行为。无论是在什么时候,我们都不清楚自己位于哪个线程之上,我们可以调用Dispatcher.CheckAccess()来决定是否可以访问任意用户界面控件。如果需要从线程边界执行调用,就必须使用Dispatcher.Invoke()。Dispatcher.Invoke()方法避免了由于使用了方法参数的参数数组而造成的若干超载问题。它使用的是一个我们想要执行的抽象代表类型。

你想要一个能检查是否需要整理编排的单一方法。如果需要,则方法会编排好调用,否则,会调用由代表指定的方法。你虚伪方法作为System.Windows.Controls.Control 类型的成员出现。这样使得你可以将代码作为控件的一部分来使用。C#3.0就为你提供了这样做的方法:扩展方法。你需要编写一些方法的不同超载,这些使得你可以通过不同的参数来使用它们:


public static class WPFExtensions:
{
public static voidInvokeIfNeeded(
this Control widget,
Action whatToDo)
{
if (!widget.Dispatcher.
CheckAccess())
widget.Dispatcher.Invoke(whatToDo);
else
whatToDo();
}
public static void
InvokeIfNeeded(
this Controlwidget, Action
whatToDo, T parm)
{
if (!widget.Dispatcher.CheckAccess())
widget.Dispatcher.Invoke(whatToDo, parm);
else
whatToDo(parm);
}
public static void
InvokeIfNeeded(this
Controlwidget, Action
whatToDo,
T1 parm1, T2 parm2)
{
if (!widget.Dispatcher.
CheckAccess())
widget.Dispatcher.
Invoke(whatToDo,
parm1, parm2);
else
whatToDo(parm1, parm2);
}
}


当然,我们也可以通过添加更多参数的方式来添加更多超载以扩展这个类。这其实是一个简单的扩展。



有一种方法让WPF设计师们疯狂:他们希望用最小化应用程序接口的面积部分来简化Dispatcher对象的使用。通过使用抽象代表和参数列表中的参数,这一对象的使用范围被扩大了。
      任何带有参数的方法都可以被拿来使用。但是,这样做有一个不足之处。该应用程序接口更为抽象,它会破坏所有类型的安全性,而且这样做会损坏编译器使用类型推理的能力,从而降低工作效率。需要做的应该是添加自己的安全扩展方法的层类型,这一层类型可以在类型安全调用和更为抽象的.NET库应用程序接口之间提供一个层。
娱乐休闲专区A 影视预告B 音乐咖啡C 英语阶梯D 生活百科
网页编程专区E AMPZF HTMLG CSSH JSI ASPJ PHPK JSPL MySQLM AJAX
Linux技术区 N 系统管理O 服务器架设P 网络/硬件Q 编程序开发R 内核/嵌入
管理中心专区S 发布网址T 版主议事U 事务处理