这篇文章很不错,推荐大伙儿都看看

Tips and Tricks
Contents
Flicker free drawing in controls
Embedding bitmaps in your manifest
Creating type safe collections the quick way
Flicker free drawing in controls
You have just spent several days writing a beautiful looking custom control but are faced with one last problem that is spoiling the whole effect. Whenever the control is redrawn it flickers. This is most obvious when the control is being resized and so redrawn many times in succession.

Solving this problem is very easy with the .NET Framework. If you come from a C++ and GDI background then the solution was to create a memory based bitmap, draw the control onto the bitmap and then blit this to the screen (otherwise known as double buffering). This is such a common requirement that the UserControl class actually implements this functionality for you. All you need to do is include the following two lines of code into your class constructor.

    SetStyle(ControlStyles.DoubleBuffer, true);
    SetStyle(ControlStyles.AllPaintingInWmPaint, true);

The first line will request that double buffering be used whenever the OnBackground or OnPaint methods are called. This will reduce then amount of flicker but may not remove it completely as painting the whole control still results in two separate blitting operations.

The second line of code above is used to ensure that only a single blitting operation occurs when drawing. This occurs when the underlying windows WM_PAINT message is processed. When this happens it will create the memory bitmap, call the OnBackground method, call the OnPaint method and then finally blit then result to the screen.

The only drawback to this technique is the greater use of resources. However, most controls are relatively small in screen size and so this is unlikely to be an issue.

Embedding bitmaps in your manifest
Usually a bitmap will be embedded into your assembly automatically, just by being associated with a property of a Form using the designer. But there are many circumstances where you may want to embed a bitmap (or other resource) without associating it with any particular Form .

You can do this in Visual Studio .NET by right-clicking the project of interest and selecting the 'Add Existing Item' option. Navigate to your bitmap and selecting it will make it appear in your project details. Now select the bitmap and modify the 'Build' property to become 'Embed as resource'. Rebuild your project and then use the ILDAsm.exe utility to examine the manifest for your built assembly. You will now see that the bitmap has been added as a resource.

To extract this resource at runtime is not obvious with only involves three steps.

    // Get the assembly we are built into
    Assembly myAssembly = Assembly.GetAssembly(Type.GetType("MyNamespace.ThisClass"));

    // Get the resource stream containing the embedded resource
    Stream imageStream = myAssembly.GetManifestResourceStream("Example.bmp");

    // Load the bitmap from the stream
    Bitmap pics = new Bitmap(imageStream);

The first line of code is used to get a reference to the assembly this code is built into. In your own code you should substitute the 'MyNamespace.ThisClass' string for the fully qualified name of the class the code is inside.

The second line requests from the assembly a stream that contains the contents of the named resource. This name will need to match the name that appears when using the ILDAsm.exe utility. Visual Studio will create this name as the default namespace appended with the name of the file. If your code generates an exception at this point then double check the name you provide exactly matches that inside the manifest.

The last line of code is obvious and simply uses the Bitmap constructor that takes as input a Stream .

If you prefer to build your projects manually without Visual Studio then you can still use the same technique. Just use the /resource:Example.bmp option in your csc command to cause the bitmap to be embedded. In which case the name in the manifest will exactly match the resource filename rather than be modified by Visual Studio.

Creating type safe collections the quick way
Often when writing your own class you need to expose a collection of items to the caller. Usually the caller will also need to modify that collection at runtime. For example, a TabControl has a collection of TabPage objects that the caller can modify to add and remove pages.

Although creating a collection class is not difficult it can be time consuming. Rather than begin from scratch it is much easier to derive from the framework class CollectionBase. This class will handle the management of the collection for us by using an ArrayList instance internally.

Two tasks however remain. First we need to generate events when the contents of the collection change, so that our class can perform appropriate actions. For example, when a new TabPage is added to a pages collection the TabControl would need to be notified of this so it can change the appearance appropriately. To achieve this we define a new class called CollectionWithEvents as shown below.

public class CollectionWithEvents : CollectionBase
{
    // Declare the event signatures
    public delegate void CollectionClear();
    public delegate void CollectionChange(int index, object value);

    // Collection change events
    public event CollectionClear Clearing;
    public event CollectionClear Cleared;
    public event CollectionChange Inserting;
    public event CollectionChange Inserted;
    public event CollectionChange Removing;
    public event CollectionChange Removed;
    
    // Overrides for generating events
    protected override void OnClear()
    {
        if (Clearing != null) Clearing();
    }        
    
    protected override void OnClearComplete()
    {
        if (Cleared != null) Cleared();
    }    

    protected override void OnInsert(int index, object value)
    {
        if (Inserting != null) Inserting(index, value);
    }

    protected override void OnInsertComplete(int index, object value)
    {
        if (Inserted != null) Inserted(index, value);
    }

    protected override void OnRemove(int index, object value)
    {
        if (Removing != null) Removing(index, value);
    }

    protected override void OnRemoveComplete(int index, object value)
    {
        if (Removed != null) Removed(index, value);
    }
}

Our second task is to ensure that the collection class is type specific. So we derive a type specific class from the CollectionWithEvents base class and expose the set of methods the caller needs to manipulate it. For example, a collection to manipulate objects of type MyType would look like the following.

public class MyTypeCollection : CollectionWithEvents
{
    public int Add(MyType value)
    {
        return base.List.Add(value as object);
    }

    public void Remove(MyType value)
    {
        base.List.Remove(value as object);
    }

    public void Insert(int index, MyType value)
    {
        base.List.Insert(index, value as object);
    }

    public bool Contains(MyType value)
    {
        return base.List.Contains(value as object);
    }

    public MyType this[int index]
    {
        get { return (base.List[index] as MyType); }
    }
}

The advantage of this design is that any additional collections we need involve creating just a single class identical to the one above but with the MyType replaced with whichever new type we desire.

Using the collection is very simple. Here is an example class that creates and exposes a collection for manipulation by the caller. The constructor hooks into some of the events it exposes in order to perform whatever implementation actions is needs.

class Example
{
    protected MyTypeCollection _collection;
    
    class Example()
    {
        // Create the new but empty collection
        _collection = new MyTypeCollection();

        // Hookup to whichever events are of interest
        _tabPages.Cleared += new CollectionWithEvents.CollectionClear(OnClearedPages);
        _tabPages.Inserted += new CollectionWithEvents.CollectionChange(OnInsertedPage);
        _tabPages.Removed += new CollectionWithEvents.CollectionChange(OnRemovedPage);
    }

    public MyTypeCollection MyTypes
    {
        get { return _collection; }
    }

    public MyType this[int index]
    {
        get { return _collection[index]; }
    }

    protected void OnClearedPages()
    {
        // TODO...your actions
    }

    protected void OnInsertedPage(int index, object value)
    {    
        MyType obj = value as MyType;
        // TODO...your actions
    }

    protected void OnRemovedPage(int index, object value)
    {
        MyType obj = value as MyType;
        // TODO...your actions
    }
}

The above example only hooks into the events that occur after the collection has been altered. In practice you will probably also want to hook into those that occur before the collection is modified.

时间: 2024-11-01 19:39:34

这篇文章很不错,推荐大伙儿都看看的相关文章

这篇文章很好的诠释了为什么安全框架如此重要?

本文讲的是这篇文章很好的诠释了为什么安全框架如此重要?,很多安全公司没有研究.开发和实现各种各样的项目框架不也运营的还行么?那我们为什么还要专门弄个团队来干这事儿呢?然而,"运营得还行"本身就是答案的一部分.在缺乏可见后果的情况下,安全主管和从业员工需要遵循框架来更有效理解自己的工作. 首先,得承认信息安全是一门历史不足30年的新兴学科.与IT其他方面和非计算机相关产业相比,信息安全还只处于婴儿期.不过,随着这一行业的成熟发展,杰出的领导者们开始共享自己的成功与困难,发展出供其他人遵循

关于python解释器的几篇文章,非常不错

关于python解释器的几篇文章,非常不错 原文地址: http://akaptur.github.io/blog/categories/python-internals/ http://akaptur.github.io/blog/2013/11/15/introduction-to-the-python-interpreter/http://akaptur.github.io/blog/2013/11/15/introduction-to-the-python-interpreter-2/h

在网上看到这篇文章还不错,OnDrawItem与DrawItem讨论

我在学习中经常遇到要重写DrawItem()的情况,但又有一个WM_DRAWITEM消息,它们是什么样的关系呢.如果我们要重写一个CButton取名为CMyButton,我们可以重写CMyButton的DrawItem()函数来实现我们的 需求,但CMyButton::DrawItem()是在什么时候调用呢?它是在它的宿主类的OnDrawItem()中被调用, OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct )正是对WM_DRAW

硬盘修理方面的两篇文章——硬盘维修与数据恢复第1/2页_其它相关

费了很大力气去贴这两篇文章,觉得值得,用电脑这么长时间也遇见过很多的硬盘问题,很多问题都无功而返.让我很痛心的是人为造成硬盘数据的丢失,这样的回数有好几次,有一段时间看过这方面的资料,以前想做了一个"数据恢复之不完全手册"也从未动过,没有条件时想去创造条件,等有了条件却又不去做...... 软件能够修复硬盘吗?--硬盘损坏全分析 作者:致鸣前言 这是作者致鸣写给我的一段话:"想写这篇文章很久了,之所以一直没有动笔,是因为碍于个人的责任感,担心自己所掌握的知识面不够,不能全面.

很不错的文章---【问底】徐汉彬:亿级Web系统搭建——单机到分布式集群

原文:很不错的文章---[问底]徐汉彬:亿级Web系统搭建--单机到分布式集群 [导读]徐汉彬曾在阿里巴巴和腾讯从事4年多的技术研发工作,负责过日请求量过亿的Web系统升级与重构,目前在小满科技创业,从事SaaS服务技术建设.  大规模流量的网站架构,从来都是慢慢"成长"而来.而这个过程中,会遇到很多问题,在不断解决问题的过程中,Web系统变得越来越大.并且,新的挑战又往往出现在旧的解决方案之上.希望这篇文章能够为技术人员提供一定的参考和帮助.  以下为原文 当一个Web系统从日访问量

推荐一篇文章

防止使用者按上一頁按鈕 討論區上常有網友問到這個問題, 如何防止使用者按回上一頁按鈕, 為何會問這一個問題? 應該通常是在防止使用者重複執行一個應用程式, 例如資料庫的新增, 如果使用者按了回上一頁, 有可能會造成重複新增資料, 今天這篇文章就要介紹如何 "盡可能" 的防止使用者按回上一頁 伺服端防止快取 首先來看看伺服端的方法, ASP 的 Response 物件提供了幾個網頁快取 (cache) 相關的屬性, 說明如下 屬性 說明 CacheControl 判斷代理伺服器 (Pro

平台选择很重要:30天25篇文章、60W阅读量

导读:互联网的平台有很多,在大家都扎堆微信的时候,有人也另辟蹊径去一些竞争相对较弱的平台,同样也能有所成就.也不要死死的抱住自己的网站那一点点可怜的流量不放,互联网的世界很大,很多平台都能创造价值.例如今天本文要分享的案例. 早之前就听说有些牛人在今日头条发的文章能获得千万点击,掐指一算,这尼玛是我博客一年的才能到达的数据啊.当时还是持半信半疑的态度,后面壹起航的青哥把他的后台数据截图发给我看,这次真信了: (数据截至日期为http://www.aliyun.com/zixun/aggregat

推荐最近收藏的几篇文章(r12笔记第85天)

  今天突然想起来,我微信里还真收藏了不少有意思的视频和文章,我也筛选一下,也和大家交流交流,当然基本都是和技术无关的,每篇文章我也写出一点感想,表明我是认真对待这个事情的,把文章读完了的,下列的文章排名不分先后,是按照我收藏的顺序来. 1)蜂王浆的神话 说实话,我感觉方舟子有些言论是过激的,甚至我对他有些反感,但是最近看了他的一些科普的文章,发现写得很深刻,发现这里面的门道确实很多,小时候的大补蜂王浆原来是这么回事. 文章链接: http://mp.weixin.qq.com/s/SBuZBc

看到这篇文章的朋友们都有自己的答案和固有认知

陌陌是什么工具,相信看到这篇文章的朋友们都有自己的答案和固有认知,不用方雨再给大家脑补. 陌陌至今总注册用户数达到1.48亿,月活跃用户数5243万.早在前年,微博上就有用户和方雨探讨如何用陌陌做推广.方雨时不时登陆也有看到一些嗅觉灵敏的朋友圈卖家利用它做广告,卖理财产品的.数码二手买卖的.大牌A货.化妆品等.海量用户的汇集自然而然具有营销价值,对于很多商家来说,陌陌已经成为一个具有营销价值的平台.去年方雨开始做微信培训时,也一直有跟那批民营医疗的朋友讲,陌陌是不可忽视的营销平台,如今陌陌几乎成