-

看见CSDN论坛上面还是有蛮多群广告的,在就冒死做个广告。

 我开的QQ群:62162267, 已经有一百多人了,

注重讨论winform, wpf 等windows 平台桌面软件开发的知识, Infragistics 第三方控件, NHibernate, smartclient 等等。各位赏脸,欢迎加入互相交流

posted @ 2009-03-19 17:34 杨同学 阅读(229) 评论(1) 编辑

     调用Control.DrawToBitmap(Bitmap) 方法是很容易得到控件的图形的。 但是bitmap是栅格化图形。栅格化图形有很多缺点,比如文件体积比较大、 放大后失真、 不易编辑等等。 这里教你如何导出一个控件的矢量图。

 

I.  Windows MetaFile.
     windows MetaFile 是windows 下面的一种矢量图形格式。 事实上WMF 只是记录下来的一串GDI 命令,重新调用一次这一串GDI命令就可以重建之前记录下来的图像。而大部分windows应用程序的界面都是用GDI绘制的,所以理论上都可以导出他们界面的矢量图。 详细去看:http://en.wikipedia.org/wiki/Windows_Metafile

 

II. 绘图表面 ( drawing surfaces )
     用GDI+绘图的时候,基本上你会把图形绘制到 屏幕上的窗体、传到打印机的打印文档、内存里的图像文件等等。 这些叫做绘图表面。


首先我们来创建一个新的EMF文件:

Code

 

调用WinApi把控件打印到此Graphics 对象上面(这个Graphics对象会作为参数传递给下面一级一级的子控件的OnPaint()函数):

Code

 

 到这里已经得到了这个控件的矢量图了。下面附加一段代码把这个EMF复制到剪切板上面去:

Code

 

 

运行这段代码以后, 就可以吧控件的矢量图粘贴到图像编辑软件上面了(CorelDraw, Word, Excel等)。 可以无限放大不失真, 还能够编辑里面的文本哦!

 

posted @ 2009-02-25 16:06 杨同学 阅读(2357) 评论(11) 编辑
摘要: 昨晚刚从微软官方网站上看到, 新的 .net3.5 的一系列认证出台了阅读全文
posted @ 2008-06-27 12:36 杨同学 阅读(2973) 评论(18) 编辑
        前段时间在弄CAB (Composite UI Application Block), 按着书上写的方法写了一个模块workitem extension 扩展类。当被扩展的workitem的run方法被调用的是时候,扩展类所重写的方法老是没有被调用。书上说可以我测试却不可以,搞得那天好心烦。设断点调试,明明看到workitemExtensionService 里面注册了我的那个extension。 extension 里面的OnRunStarted就是没有被调用到,我崩溃了。 后来没有办法去看CAB的源码,检查了一个晚上终于发现了一个天大的秘密, 这是一个BUG!!!!!!!!
        我们来看一下CAB的默认moduleloader :
        private void InnerLoad(WorkItem workItem, IModuleInfo[] modules)
        
{
            
if (modules.Length == 0)
                
return;

            LoadAssemblies(modules);
            List
<ModuleMetadata> loadOrder = GetLoadOrder();

            
foreach (ModuleMetadata module in loadOrder)
                module.LoadServices(workItem);

            
foreach (ModuleMetadata module in loadOrder)
                module.InitializeModuleClasses(workItem);

            
foreach (ModuleMetadata module in loadOrder)
                module.InitializeWorkItemExtensions(workItem);

            
foreach (ModuleMetadata module in loadOrder)
                module.NotifyOfLoadedModule(OnModuleLoaded);
        }
       
        模块装载的时候Load方法会先检查一下传进来的参数有没有null值这些问题, 然后转而调用到上面的这个 InnerLoad方法来装载模块。这个方法依次的 装载服务、 初始化模块、 初始化workitem extension、 然后触发模块装载完毕事件....

        起初我怀疑我的workitemextension 挂钩到workitem里面的时机晚了, 果然不出我所料。 我们看一下 ModuleMetaData 类的 InitializeModuleClasses 方法
            public void InitializeModuleClasses(WorkItem workItem)
            
{
                
if (modulesInitialzed)
                    
return;

                modulesInitialzed 
= true;
                EnsureModuleClassesExist(workItem);

                
try
                
{
                    
foreach (IModule module in moduleClasses)
                    
{
                        module.Load();

                        
if (traceSource != null)
                            traceSource.TraceInformation(Properties.Resources.ModuleStartCalled, module.GetType());
                    }

                }

                
catch (FileNotFoundException ex) { ThrowModuleReferenceException(ex); }
                
catch (Exception ex) { ThrowModuleLoadException(ex); }
            }
       而模块的InitializeModuleClasses 方法竟然调用了 IModule.Load() 方法!! 也就是说如果我在所 重写的 ModuleInit.Load() 方法里面开始我的逻辑的话, 此时workitemextension 还没有被初始化,还没有挂钩到所扩展的workitem里面!!!     而CAB附带的几个quick start 却恰恰在重写的ModuleInit.Load()方法里面开始逻辑,也就是说在模块装载还没有完全完成的时候就已经开始逻辑了!! 严重误导,严重浪费了我的时间......

       看来要自己找方法解决了。那个NotifyOfLoadedModule 是最后的步骤, 这个步骤会触发 ModuleLoader.Loaded 事件。 这才是真正的装载完毕! 于是我改为在 ModuleLoaded 的loaded 事件发生的时候开始我写的逻辑。
       贴一下我写的代码:
    public class PressureExplorerModuleInit : ModuleInit
    
{
        
private WorkItem shellRootWorkItem;

        
// the root work item of the shell will be given by constructor injection
        [InjectionConstructor]
        
public PressureExplorerModuleInit(
            [ServiceDependency] 
            WorkItem shellRootWorkItem)
        
{
            
this.shellRootWorkItem = shellRootWorkItem;
            shellRootWorkItem.Services.Get
<IModuleLoaderService>().ModuleLoaded += new EventHandler<Microsoft.Practices.CompositeUI.Utility.DataEventArgs<LoadedModuleInfo>>(PressureExplorerModuleInit_ModuleLoaded);
        }


        
private void PressureExplorerModuleInit_ModuleLoaded(object sender, Microsoft.Practices.CompositeUI.Utility.DataEventArgs<LoadedModuleInfo> e)
        
{
            
if (e.Data.Assembly == System.Reflection.Assembly.GetExecutingAssembly())
                Loaded();
        }


        
private void Loaded()
        
{
            
// start the peWorkItem after the module is fully loaded by calling run method
            PEWorkItem peWorkItem = shellRootWorkItem.WorkItems.AddNew<PEWorkItem>("PEWorkItem");
            peWorkItem.Run();
        }

    }

       至此还没有结束,虽然那我的问题解决了, 但是我还是想到网上别人有什么更好的解决方法。 然后我找到了一篇文章有关新的 new module loader for CAB, 此模块装载器修正了我所说的这个bug, 还提供了一些很有用的新功能:

Towards the end of the Smart Client Software Factory project, we wanted to be able to support a more comprehensive module loader system for CAB applications. Our goals were:

    1. Support grouping modules together into logical "sections" which represented groups of functionality. These groups might be things like "layout", "services", "applications", etc.
    2. Allow dependencies to be expressed between these sections (i.e., make sure you load all the layout modules before you load the application modules).
    3. Allow dependencies to be expressed in an external place instead of forcing them to be expressed in attributes on the assembly.
    4. Make it easier to provide transports for the profile catalog XML without having to write an entirely new enumerator.
    5. If possible, preserve backward compatibility with the new loader and old enumerators, so that we could preserve effort people had putting into writing their own enumerators.
    6. Fix a bug in the module loader that causes WorkItem extensions to be registered too late to see WorkItems that were being created in the module's Load method.


    1.  支持把模块按功能分组, 每一组模块(模组section)  代表一系列有关的功能 。 比如 “排版” 模组,“服务” 模组, “应用” 模组等等。
    2.  允许表达 section 之间的关系依赖性(耦合), 比如你可以确定 排版section 会在 应用section 装载完毕之后再装载。
    3.  允许在外部定义 关系依赖性,突破原先的只能在assembly attribute里面定义的局限。
    4.  不需要写整个 模块枚举器来实现 profile catalog XML 的传输。
    5.  向后兼容, 可以使用之前写好的 模块枚举器。
    6.  修正了我上面所描述的那个bug, 这个bug 使得 WorkItem extension 注册晚了 ( 注册聆听workitem的RunStarted, Initialized等事件晚了 )。

posted @ 2008-06-16 14:34 杨同学 阅读(1338) 评论(6) 编辑
      NHibernate 为了优化性能, 提供了自己的 custom collection(ie. bag, set ...)。 当我们定义一个one-many mapping 的时候, 应当在父类里面定义IList<child> children; 这样的一个集合(NH1.2 里面的所有集合类都实现 IList 接口 )。然而NHibernate自身提供的集合并没有implement  IBindingList<T> , 也就是说如果我们使用NHibernate将无法实现.net 2.0 里面的complex databinding。 我想这点是NHibernate团队把 Hibernate照原样搬到.net 里来的时候所没有想到的,因为java里面没有databinding这个东东。
      怎么办呢?这问题困惑了我很久,看来只能从新写一个集合类来实现数据绑定了(实现IBindingList<T> 的NHibernate 自定义集合类)。看起来还是蛮吓人的,就为了这个数据绑定写一个集合类。 还好我比较聪明,去网上找了一下看看有没有相关的资料, 找到了这个好东东: NHibernate.Databinding
      这是一个开源的NHibernate 扩展dll,专门为了支持complex binding做的。

具体使用方法,
      1. 先吧NHibernate.Databinding.Dll 添加到项目中。
      2. 把原有的集合类(bag) 替换成 BindingSet。
      3. 使用 BindingSet.GetInstance<T>()  generic方法生成BindingSet的实例  (不知道为什么不用constructor, 这里应该不会是用了singleton pattern呀,奇怪)
      4. 在hbm 映像文件里面使用set 集合来指定BindingSet这个集合的类型。
      5. 在hbm 文件里面指定使用 NHibernate.Databinding.dll 里面定义的accessor (当你存取你的object的时候,此accessor类被NHibernate 用来通过反射的途径从你的object的member variable 或者property中取值或者赋值,详细可以看Hibernate文档中hbm映像文件里 对access attribute的说明。)
   
          贴一段我写的代码:
        private BindingSet<Plot> plots = BindingSet.GetInstance<Plot>();

        
public BindingSet<Plot> Plots
        
{
            
get
            
{
                
return plots;
            }

        }

        Hibernate Mapping:
      <set name="Plots" cascade="all" lazy="true" inverse="true"
         access
="NHibernate.DataBinding.BindingAccessor+CamelCase, NHibernate.DataBinding">
          
<key column="PVAuto" />
          
<one-to-many class="RWeb6.BO.FormationPressure.Plot, RWeb6.BO.FormationPressure" />
      
</set>


       由于NHibernate.Databinding.BindingSet 这个类实现了 IBindingList<T> 接口,而此接口定义了ListChange事件,自此我们可以把他用来实现complex binding了!



有意交流或者有问题的可以加我QQ:247701287
posted @ 2008-05-20 23:12 杨同学 阅读(303) 评论(0) 编辑
摘要: 给项目的图表做了一个手工具,用来拖动图表(类似photoshop里面的手工具)。 但是把Chart鼠标指针换成找来的手指针以后运行程序以后,原本蓝色的指针却在图标上面显示出来却是黑白的了,丑的要死。 改变默认指针我用的是这行代码:Chart.Cursor = new Cursor("hand.cur"); 其中"hand.cur" 是手指针文件名。 当时我就很疑惑不解,为什么彩色的指针变成黑白...阅读全文
posted @ 2008-04-08 18:57 杨同学 阅读(863) 评论(1) 编辑