标签归档:C#

C#

在Unity Android 程序中使用动态库及注意事项

很多C/C++代码以动态库的方式供第三方调用,在Unity中,这类文件(dll for windows, *.so file for Android/Linux, *.dylib for MAC OSX)叫插件。

在Unity开发的Android程序中使用动态库插件是非常方便的,曾经因为被误导而放弃使用unity,转而研究Android通过原生Java的JNI方式包装*.so文件,虽然还行,但是JNI晦涩丑陋的API实在看着不舒服。相对而言,C#也是可以直接包装*.so文件并在Android系统中直接调用的,而且Unity制作Android app跟Unity制作其他平台的app是无缝的,只是在发布时选择要发布的平台就行了,真正做到了平台无关,极大的方便了开发。

我还没仔细研究如何在Android Studio中开发NDK,这里只介绍如何用Eclipse开发NDK。

在Eclipse中开发NDK的几个必须的安装项:NDK编译环境、Android SDK直接从官网单独下载单独安装;CDT、ADT插件可以直接从Eclipse的help的插件管理中安装。

然后就可以创建项目了:

1、打开Eclipse,通过File->New Project,弹出对话框,填入项目名称:

01

2、点Next,出现Config Project窗口:

02

由于只用于编译NDK,所以把前两项的钩钩去掉,第三个勾上,标记为so项目;目录也自定义一下,因为通常情况下我只会为编译so文件配置项目,真正的代码会单独放在更顶层的目录,方便跨平台的其他编译项目使用。结果如下:

03

4、按Finish结束创建过程,目录结构如下:

04

5、添加Native代码支持。也就是JNI相关的东西:在左侧项目根目录上右键->Android Tools->Add Native Support…

05

在随后弹出的对话框中输入要生成的so文件的名字:

06

这时候会发现多了一个目录:

07

6、编译配置

在jni目录中加入Application.mk文件和Android.mk文件

Application.mk:

APP_ABI      := all
#APP_ABI       := armeabi-v7a
#APP_ABI       += armeabi

#APP_OPTIM        := release
APP_PLATFORM     := android-8
#APP_BUILD_SCRIPT := Android.mk

# GNU STL implements most C++11 features. Use either gnustl_static or gnustl_shared
# Without this your C++ code will not be able to access headers like <thread>, <mutex>
#APP_STL := stlport_static
#APP_CPPFLAGS := -std=c++11 -frtti -fexceptions 
APP_STL       := gnustl_static
APP_CPPFLAGS  := -std=gnu++11 -pthread -frtti -fexceptions -DNDEBUG #-NDEBUG -mfpu=neon -fomit-frame-pointer -DULM_BLOCKED -msse3 -mfpmath=sse

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := PNLib
LOCAL_SRC_FILES := PNLib.cpp

include $(BUILD_SHARED_LIBRARY)

本来Android.mk文件很简单,把所有头文件、cpp文件加入,直接编译就行。但是对于我的项目这远远不够,因为我的代码要跨平台,有各个平台的编译项目单独出去,同时使用一份src文件,所以代码被放到了顶层目录中的src目录下,我需要遍历这个目录并把它加入NDK编译系统中来,所以下面从网上找了一段遍历头文件和cpp文件的脚本来用了:

# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE   := PNLib

# 锟斤拷锟斤拷锟皆硷拷锟斤拷源锟侥硷拷目录锟斤拷源锟侥硷拷锟斤拷缀锟斤拷
MY_FILES_PATH  :=  $(LOCAL_PATH)/../../src

#$(warning $(MY_FILES_PATH))

MY_FILES_SUFFIX := %.cpp %.c

# 递归遍历目录下的所有的文件
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

# 获取相应的源文件
MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) ) 
MY_ALL_FILES := $(MY_ALL_FILES:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%)
MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES)) 
MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)

# 去除字串的重复单词
define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
  ${seen}
endef

# 递归遍历获取所有目录
MY_ALL_DIRS := $(dir $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*/) ) )
MY_ALL_DIRS := $(call uniq,$(MY_ALL_DIRS))

# 赋值给NDK编译系统
LOCAL_SRC_FILES  := $(MY_SRC_LIST)
LOCAL_C_INCLUDES := $(MY_ALL_DIRS)

# Add additional include directories
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../Eigen-3.2.2   
#必须从Android.mk配置文件中拿掉对Eigen的直接包含,放到程序代码中用相对路径包含:
# #include "../../Eigen-3.2.2/Eigen"
# using namespace Eigen;

#$(warning $(LOCAL_SRC_FILES))
#$(warning $(LOCAL_C_INCLUDES))

# use log system in NDK
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

7、最后一步是为此项目配置一个NDK编译工具:

A、项目->右键->Properties,弹出项目属性对话框:

08

B、选中Builders,点击New按钮,弹出框中选中“Program”,点击OK:

09

C、出现新Builder配置对话框,随便起个名字“New_Builder_for_NDK”;

在Main标签页中,“Location”项,通过“Browse File System…“找到NDK的build文件,windows系统为ndk-build.cmd,Mac或其他类Linux系统为ndk-build;

工作目录”Working Directory“指定当前项目下的jni目录就行了。

10

D、切到Refresh页,勾选”Refresh resources upon completion“

11

E、切到”Build Options“页,勾选”Specify working set of relevant resources“,点击后面按钮”Specify Resources…“,指本项目下的jni目录。

12

最后的编译条如下:

13

点击左边锤子图标即可对项目进行编译。剩下的工作就是一步步修正跨平台代码,最后生成PNLib.so文件。

 

以上步骤有几个地方需要特别注意:

1、使用gun++11

NKD支持c++11,GCC已经支持大部分c++11特性,所以可以直接使用gun++11。实际上,如果用c++11,Android版程序可能报错:DLLNotFundException,编译出来的动态库在Android系统中无法加载,所以Application.mk文件中必须如下配置:

APP_STL       := gnustl_static
APP_CPPFLAGS  := -std=gnu++11 -pthread -frtti -fexceptions -DNDEBUG

2、x64版ndk目前还有bug

你的系统即便是x64的,也别下载x64版本的ndk,否则会报找不到make.exe的问题(make.exe不是内部命令XXXXXXXXX)

 

3、不识别vector、list等模板类的问题

Add

APP_STL := stlport_static

to their Application.mk file.

其实Android插件应该用APP_STL := gnustl_static

 

4、使用第三方库Eigen导致array等冲突的问题

原因是在NDK的Android.mk文件中把Eigen的路径也加入到里面了。

正确的做法是,不在Android.mk文件加入Eigen,而是在程序代码中直接包含Eigen头文件。

 

从C++的dll中Callback到C#返回数组:只取到了第一个元素

假设C/C++的dll中定义回调函数:

// Received data callback
typedef void(__stdcall *ReceivedDataCallback)(SerialPortRef sp, unsigned char* data, int len);


/*********************************************************
* Library API definitions *
/*********************************************************/
#ifdef __cplusplus
extern "C" {
#endif

 // Register handl to receive data from a SerialPort.
 SERIALPORTRW_API void RegisterReceivedDataCallback(SerialPortRef sp, ReceivedDataCallback handle);

//......................

C#中包含dll,通过包装dll的函数和回调函数,以便dll中收到数据时回调到C#:

// Wrapper of library by C#
namespace PluginImport
{
	#region delegates
    public delegate void ReceivedDataCallback(IntPtr serialPortRef, [MarshalAs(UnmanagedType.LPArray)]byte[] data, int len);
	#endregion
		
	#region API Wraper
	public class SerialPortDevice
	{
		// Register handl to receive data from a SerialPort.
		[DllImport("SerialPortDevice", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
        public static extern void RegisterReceivedDataCallback(UIntPtr sp, ReceivedDataCallback handle);

使用此DLL包装的API:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ReceivedDataCallback = (IntPtr serialPortRef, byte[] data, int len) =>
            {
                byte[] localData = data;

                this.Dispatcher.Invoke(new Action(() => { tbLog.Text += ByteUtils.bytesToHexString(localData, 0, len); }));
            };

            SerialPortStatusChanged = (IntPtr serialPortRef, SerialPortStatus status, string msg) =>
            {
                this.Dispatcher.Invoke(new Action(() => { tbLog.Text += "\r\n" + msg; }));
            };


            spRef = SerialPortDevice.CreateSerialPort();
            if (spRef != UIntPtr.Zero)
            {
                SerialPortDevice.RegisterReceivedDataCallback(spRef, ReceivedDataCallback);
                SerialPortDevice.RegisterSerialPortStatusChangedCallback(spRef, SerialPortStatusChanged);
            }

发现上面红色部分的data的长度总是一个字节。

原因:

marshaller不知道data的长度到底是多少,只是简单的按照数据类型返回了数组中的第一个元素,根本没有办法marshal。

正确的做法是将data定义为指针,然后通过拷贝的方法将数据取到C#端:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ReceivedDataCallback = (IntPtr serialPortRef, IntPtr data, int len) =>
            {
                byte[] localData = new byte[len];
                Marshal.Copy(data, localData, 0, len);
                
                string strHex = ByteUtils.bytesToHexString(localData, 0, len);

                this.Dispatcher.Invoke(new Action(() => { tbLog.Text += "\r\n" + strHex; }));
            };

            SerialPortStatusChanged = (IntPtr serialPortRef, SerialPortStatus status, string msg) =>
            {
                this.Dispatcher.Invoke(new Action(() => { tbLog.Text += "\r\n" + msg; }));
            };


            spRef = SerialPortDevice.CreateSerialPort();
            if (spRef != UIntPtr.Zero)
            {
                SerialPortDevice.RegisterReceivedDataCallback(spRef, ReceivedDataCallback);
                SerialPortDevice.RegisterSerialPortStatusChangedCallback(spRef, SerialPortStatusChanged);
            }
        }

当然,在这之前要在C#端的回调函数定义中的数据也要改成指针:

public delegate void ReceivedDataCallback(IntPtr serialPortRef, IntPtr data, int len);

 

博客搬家

过两天有时间,我会把博客园(http://www.cnblogs.com/khler)的内容搬迁到这里,到时候内容就充实多了:)

网上找了一下从博客园搬家到wordpress的工具,还真没有好用的。找到“武眉博<活靶子.Net>”自己弄的一个小工具,应该还不错,可惜我用了一下,里面很多参数都是针对他自己的blog的,需要花些时间修改。

工具地址:http://huobazi.aspxboy.com/2009/06/21/my-blog-moved-to-wp/

先收藏,有时间整理个更通用点的,如果武兄允许,可以开源给大家用,造福百姓:)

【转】典型开源3D引擎分类比较

 

典型开源3D引擎分类比较

 

常见的3D引擎有:Unreal,Quake,Lithtech,OGRE,Nebula,Irrlicht,Truevision3D…等,其中开源免费的有:orge,irrlicht,fly3d, NeoEngine, revolution3d, Nebula2Genesis3d等。OGRE 在免费、开源的引擎中评价最高,一个原因是作为一个图形渲染引擎,它支持的图形特性最多,所以渲染质量也不错;另一个原因是设计模式的清晰;另外,速度也不错。OGRE 将专注于向一个纯粹的、然而富于协作和扩展性的图形引擎发展,这得益于它的庞大的社群支持,使得很多事情可以通过外挂一些更专业的引擎来实现,物理引擎使用 ODE  Tokamak  NovodeX ,网络引擎使用 openTNL  RakNet  eNet ,声音引擎使用 FMod  OpenAL ,以及界面引擎使用 CEGUI 

 

 

Standard

OGRE

IrrLicht

Truevision3D

General

Type

Only rendering engine

 

Game engine

Include TV3DEngine,TV3DMedia,TV3DNet……

Languages

Written in pure C++, totally object orientated.

Written in pure C++, totally object orientated.

Written in C++ and VB6 with DirectX8.1

License

LGPL

zlib/libpng License(totally free)

·   Free TV3DSDK

·   Registered Developer License

·   group or site licenses

Develop platforms

·   C++

·   .NET

·   C++

·   .NET language binding

VB/VC++/DELPHI/

C#/vb.net

Platforms

Windows

ü         Support

ü         Support

ü         Support

Linux

 

ü         Support

ü         Support

 

MacOS

ü         Support

ü         Support

 

3D API

Direct3D

ü         Support

ü         Support

ü         Support

OpenGL

ü         Support

ü         Support

 

Other

 

·   The Irrlicht Engine software renderer.

·   The Apfelbaum Software Renderer

 

Architecture

Extensibility

·   Extensible example framework

·   Flexible plugin architecture allows engine to be extended without recompilation

·   Use some other professional engines to achieve other features

 

 

Scripting

 

 

 

Materials & Textures

Materials

·   Powerful material declaration language

·   Multiple material

·   Material LOD

·   Multi-texture and multi-pass blending

·   Projective texturing

·   Textures can be provided and updated in real-time by plugins

·   Provide common built in materials based on fixed function pipeline or programmable pipeline

·   add new materials to Irrlicht at runtime, without the need of modifying/recompiling the engine

 

Textures and Mapping

自动产生MipMap

 

自动调整纹理大小以满足硬件需求。

 

支持可程序控制的纹理坐标生成和转换。

·   Bump mapping

·   Parallax mapping

·   Light maps

·   Sphere mapping

DOT3 Bump mapping

 

没有提供多层纹理和混合模式

Shaders

·   Supports vertex and fragment programs, both written in assembler, and in Cg, DirectX9 HLSL, or GLSL

·   Support many commonly bound constant parameters like worldview matrices, light state information, object space eye position etc

·   Pixel and Vertex Shaders 1.1 to 3.0

·   ARB Fragment and Vertex Programs

·   HLSL

·   GLSL

·   Hardware Vertex Shaders

·   HLSL

Scene Management

General

·   Highly customizable, flexible scene management, not tied to any single scene type.

·   Hierarchical scene graph; nodes allow objects to be attached to each other and follow each others movements, articulated structures etc

·   Scene querying

·   Using a hierarchical scene graph, can mix indoor and outdoor scene seamless together

·   Extensible hierarchical scene management

 

 

BSP Support

BSP 场景的天空穹、粒子特效、高级材质属性,乃至 BSP 的空间分割规则都会被正确识别、自动实现

·    BSP 的特性支持比较贫乏

 BSP 的读取存在 BUG

Other

 

 

 

Special effects

Particle System

 

·   easily extensible emitters, affectors and renderers

·   can be defined in text scripts for adjusting in real-time

·   particle pooling

·   Customizeable Particle systems for snow, smoke, fire, …

Atmospheric effects like fog, cloud, sky (box and sphere), stars.

Light & Shadow

 

当前支持三种阴影:调整纹理阴影,调整模版阴影,附加模板阴影。不支持软阴影

Multiple shadow rendering techniques,

·   Dynamic lights

·   Dynamic shadows using the stencil buffer

·   Optimized dynamic stencil shadows

·   DirectX Hardware Lighting

Other

·   Support for skyboxes, skyplanes and skydomes

·   Billboarding for sprite graphics

·   Transparent objects automatically managed

 

·   Realistic water surfaces

·   Billboards

·   Transparent objects

·   Skyboxes

·   Fog

·   Texture animation

Billboard

Character Animation

 

·   Skeletal animation

·   blending of multiple animations

·   variable bone weight skinning

·   hardware-accelerated skinning

 

·   Morph target animation:

·   Skeletal animation

·   Skeleton based, Key frame based, morph based animations

·   Animations that can be enhanced by bone attaching or custom bone rotations.

Supported Formats

textures file formats

·   PNG, JPEG, TGA, BMP or DDS

·   1D textures, volumetric textures, cubemaps and compressed textures (DXT/S3TC)

·   PSD,JPG,PNG,TGA,BMP,PCX 

 

 

mesh file formats

Milkshape3D, 3D Studio Max, Maya, Blender and Wings3D

·   3DS,OBJ,CSM,DAE,DMF,OCT,X,MS3D,MY3D,LMTS,BSP,MD2

3DS, X, MDL, MD2, MD3

Document

 

Great number of users and well documented.

well documented API with lots of examples and tutorials.

 

Other

GUI

 

 

 

2D Drawing

 

 

 

XML

ü         Support

XML Converter: convert efficient runtime binary formats to/from XML for interchange or editing

ü        Support

快速的XML分析器

 

Web Site

 

http://www.ogre3d.org

http://irrlicht.sourceforge.net

http://www.truevision3d.com

 


 本文来自:http://www.cnblogs.com/cyberchen-net/archive/2007/03/04/663597.html

 

VB.NET and C# 语法比较手册

 

VB.NET and C# Comparison
This is a quick reference guide to highlight some key syntactical differences between VB.NETand C#. Hope you find this useful!
Thank you to Tom Shelton, Fergus Cooney, and others for your input.

VB.NET

C#

Comments
‘ Single line only
Rem Single line only

// Single line
/* Multiple
    line  */
/// XML comments on single line
/** XML comments on multiple lines */

Data Types

Value Types
Boolean
Byte
Char   (example: “A”c)
Short, Integer, Long
Single, Double
Decimal
Date

Reference Types
Object
String

Dim x As Integer
Console.WriteLine(x.GetType())     ‘ Prints System.Int32
Console.WriteLine(TypeName(x))  ‘ Prints Integer

‘ Type conversion
Dim numDecimal As Single = 3.5
Dim numInt As Integer
numInt = CType(numDecimal, Integer)   ‘ set to 4 (Banker’s rounding)
numInt = CInt(numDecimal)  ‘ same result as CType
numInt = Int(numDecimal)    ‘ set to 3 (Int function truncates the decimal)

Value Types
bool
byte, sbyte
char   (example: ‘A’)
short, ushort, int, uint, long, ulong
float, double
decimal
DateTime   (not a built-in C# type)

Reference Types
object
string

int x;
Console.WriteLine(x.GetType());    // Prints System.Int32
Console.WriteLine(typeof(int));      // Prints System.Int32


// Type conversion

double numDecimal = 3.5;
int numInt = (int) numDecimal;   // set to 3  (truncates decimal)

Constants
Const MAX_STUDENTS As Integer = 25 const int MAX_STUDENTS = 25;
Enumerations
Enum Action
  Start 
  [Stop]   ‘ Stop is a reserved word
  Rewind
  Forward
End Enum

Enum Status
  Flunk = 50
  Pass = 70
  Excel = 90
End Enum

Dim a As Action = Action.Stop
If a <> Action.Start Then Console.WriteLine(a)     ‘ Prints 1

Console.WriteLine(Status.Pass)     ‘ Prints 70

Dim s As Type = GetType(Status)
Console.WriteLine([Enum].GetName(s, Status.Pass))    ‘ Prints Pass

enum Action {Start, Stop, Rewind, Forward};
enum Status {Flunk = 50, Pass = 70, Excel = 90};

Action a = Action.Stop;
if (a != Action.Start)
  Console.WriteLine(a + ” is ” + (int) a);    // Prints “Stop is 1”

Console.WriteLine(Status.Pass);    // Prints Pass

Operators

Comparison
=  <  >  <=  >=  <>

Arithmetic
+  –  *  /
Mod
(integer division)
(raise to a power)

Assignment
=  +=  -=  *=  /=  \=  ^=  <<=  >>=  &=

Bitwise
And  AndAlso  Or  OrElse  Not  <<  >>

Logical
And  AndAlso  Or  OrElse  Not

Note: AndAlso and OrElse are for short-circuiting logical evaluations

String Concatenation
&

Comparison
==  <  >  <=  >=  !=

Arithmetic
+  –  *  /
(mod)
(integer division if both operands are ints)
Math.Pow(x, y)

Assignment
=  +=  -=  *=  /=   %=  &=  |=  ^=  <<=  >>=  ++  —

Bitwise
&  |  ^   ~  <<  >>

Logical
&&  ||   !

Note: && and || perform short-circuit logical evaluations

String Concatenation
+

Choices

greeting = IIf(age < 20, “What’s up?”, “Hello”)

‘ One line doesn’t require “End If”, no “Else”
If language = “VB.NET” Then langType = “verbose”

‘ Use : to put two commands on same line
If x <> 100 Then x *= 5 : y *= 2  

‘ or to break up any long single command use _
If whenYouHaveAReally < longLine And itNeedsToBeBrokenInto2 > Lines Then _
  UseTheUnderscore(charToBreakItUp)

If x > 5 Then
  x *= y
ElseIf x = 5 Then
  x += y
ElseIf x < 10 Then
  x -= y
Else
  x /= y
End If

Select Case color   ‘ Must be a primitive data type
  Case “pink”, “red”
    r += 1
  Case “blue”
    b += 1
  Case “green”
    g += 1
  Case Else
    other += 1
End Select

greeting = age < 20 ? “What’s up?” : “Hello”;

if (x != 100) {    // Multiple statements must be enclosed in {}
  x *= 5;
  y *= 2;
}

No need for _ or : since ; is used to terminate each statement.


if
(x > 5)
  x *= y;
else if (x == 5)
  x += y;
else if (x < 10)
  x -= y;
else
  x /= y;

switch (color) {                          // Must be integer or string
  case “pink”:
  case “red”:    r++;    break;        // break is mandatory; no fall-through
  case “blue”:   b++;   break;
  case “green”: g++;   break;
  default:    other++;   break;       // break necessary on default
}

Loops
Pre-test Loops:
While c < 10
  c += 1
End While

Do Until c = 10 
  c += 1
Loop

Do While c < 10
  c += 1
Loop

For c = 2 To 10 Step 2
  Console.WriteLine(c)
Next


Post-test Loops:
Do 
  c += 1
Loop While c < 10
Do 
  c += 1
Loop Until c = 10

‘  Array or collection looping
Dim names As String() = {“Fred”, “Sue”, “Barney”}
For Each s As String In names
  Console.WriteLine(s)
Next

Pre-test Loops:  

// no “until” keyword
while (i < 10)
  i++;

for (i = 2; i < = 10; i += 2)
  Console.WriteLine(i);

Post-test Loop:

do
  i++;
while (i < 10);

// Array or collection looping

string[] names = {“Fred”, “Sue”, “Barney”};
foreach (string s in names)
  Console.WriteLine(s);

Arrays

Dim nums() As Integer = {1, 2, 3} 
For i As Integer = 0 To nums.Length – 1
  Console.WriteLine(nums(i))
Next

‘ 4 is the index of the last element, so it holds 5 elements
Dim names(4) As String
names(0) = “David”
names(5) = “Bobby”  ‘ Throws System.IndexOutOfRangeException

‘ Resize the array, keeping the existing values (Preserve is optional)
ReDim Preserve names(6)

Dim twoD(rows-1, cols-1) As Single
twoD(2, 0) = 4.5

Dim jagged()() As Integer = { _
  New Integer(4) {}, New Integer(1) {}, New Integer(2) {} }
jagged(0)(4) = 5

int[] nums = {1, 2, 3};
for (int i = 0; i < nums.Length; i++)
  Console.WriteLine(nums[i]);

// 5 is the size of the array
string[] names = new string[5];
names[0] = “David”;
names[5] = “Bobby”;   // Throws System.IndexOutOfRangeException

// C# doesn’t can’t dynamically resize an array.  Just copy into new array.
string[] names2 = new string[7];
Array.Copy(names, names2, names.Length);   // or names.CopyTo(names2, 0); 

float[,] twoD = new float[rows, cols];
twoD[2,0] = 4.5f; 

int[][] jagged = new int[3][] {
  new int[5], new int[2], new int[3] };
jagged[0][4] = 5;

Functions

‘ Pass by value (in, default), reference (in/out), and reference (out) 
Sub TestFunc(ByVal x As Integer, ByRef y As Integer, ByRef z As Integer)
  x += 1
  y += 1
  z = 5
End Sub

Dim a = 1, b = 1, c As Integer   ‘ c set to zero by default 
TestFunc(a, b, c)
Console.WriteLine(“{0} {1} {2}”, a, b, c)   ‘ 1 2 5

‘ Accept variable number of arguments
Function Sum(ByVal ParamArray nums As Integer()) As Integer
  Sum = 0 
  For Each i As Integer In nums
    Sum += i
  Next
End Function   ‘ Or use Return statement like C#

Dim total As Integer = Sum(4, 3, 2, 1)   ‘ returns 10

‘ Optional parameters must be listed last and must have a default value
Sub SayHello(ByVal name As String, Optional ByVal prefix As String = “”)
  Console.WriteLine(“Greetings, ” & prefix & ” ” & name)
End Sub

SayHello(“Strangelove”, “Dr.”)
SayHello(“Madonna”)

// Pass by value (in, default), reference (in/out), and reference (out)
void TestFunc(int x, ref int y, out int z) {
  x++;  
  y++;
  z = 5;
}

int a = 1, b = 1, c;  // c doesn’t need initializing
TestFunc(a, ref b, out c);
Console.WriteLine(“{0} {1} {2}”, a, b, c);  // 1 2 5

// Accept variable number of arguments
int Sum(params int[] nums) {
  int sum = 0;
  foreach (int i in nums)
    sum += i;
  return sum;
}

int total = Sum(4, 3, 2, 1);   // returns 10

/* C# doesn’t support optional arguments/parameters.  Just create two different versions of the same function. */ 
void SayHello(string name, string prefix) {
  Console.WriteLine(“Greetings, ” + prefix + ” ” + name);

void SayHello(string name) {
  SayHello(name, “”);
}

Exception Handling

‘ Deprecated unstructured error handling
On Error GoTo MyErrorHandler

MyErrorHandler: Console.WriteLine(Err.Description)

Dim ex As New Exception(“Something is really wrong.”)
Throw  ex 

Try 
  y = 0
  x = 10 / y
Catch ex As Exception When y = 0 ‘ Argument and When is optional
  Console.WriteLine(ex.Message)
Finally
  Beep()
End Try

Exception up = new Exception(“Something is really wrong.”);
throw up;  // ha ha

try
  y = 0;
  x = 10 / y;
}
catch (Exception ex) {   // Argument is optional, no “When” keyword 
  Console.WriteLine(ex.Message);
}
finally {
  // Must use unmanaged MessageBeep API function to beep
}

Namespaces

Namespace Harding.Compsci.Graphics 
  …
End Namespace

‘ or

Namespace Harding
  Namespace Compsci
    Namespace Graphics 
      …
    End Namespace
  End Namespace
End Namespace

Import Harding.Compsci.Graphics

namespace Harding.Compsci.Graphics {
  …
}

// or

namespace Harding {
  namespace Compsci {
    namespace Graphics {
      …
    }
  }
}

using Harding.Compsci.Graphics;

Classes / Interfaces

Accessibility keywords
Public
Private
Friend                   
Protected
Protected Friend
Shared

‘ Inheritance
Class FootballGame
  Inherits Competition
  …
End Class 

‘ Interface definition
Interface IAlarmClock 
  …
End Interface

// Extending an interface 
Interface IAlarmClock
  Inherits IClock
  …
End Interface

// Interface implementation
Class WristWatch 
  Implements IAlarmClock, ITimer 
   …
End Class 

Accessibility keywords
public
private
internal
protected
protected internal
static

// Inheritance
class FootballGame : Competition {
  …
}


// Interface definition

interface IAlarmClock {
  …
}

// Extending an interface 
interface IAlarmClock : IClock {
  …
}


// Interface implementation

class WristWatch : IAlarmClock, ITimer {
   …
}

Constructors / Destructors
Class SuperHero
  Private _powerLevel As Integer

  Public Sub New ()
    _powerLevel = 0
  End Sub

  Public Sub New (ByVal powerLevel As Integer)
    Me._powerLevel = powerLevel
  End Sub

  Protected Overrides Sub Finalize () 
   ‘ Desctructor code to free unmanaged resources
    MyBase.Finalize()
  End Sub
End Class

class SuperHero {
  private int _powerLevel;

  public SuperHero() {
     _powerLevel = 0;
  }

  public SuperHero(int powerLevel) {
    this._powerLevel= powerLevel; 
  }

  ~SuperHero() {
    // Destructor code to free unmanaged resources.
    // Implicitly creates a Finalize method

  }
}

Objects

Dim hero As SuperHero = New SuperHero
With hero
  .Name = “SpamMan”
  .PowerLevel = 3
End With

hero.Defend(“Laura Jones”)
hero.Rest()     ‘ Calling Shared method
‘ or
SuperHero.Rest()

Dim hero2 As SuperHero = hero  ‘ Both refer to same object
hero2.Name = “WormWoman”
Console.WriteLine(hero.Name)   ‘ Prints WormWoman

hero = Nothing    ‘ Free the object

If hero Is Nothing Then _
  hero = New SuperHero

Dim obj As Object = New SuperHero
If TypeOf obj Is SuperHero Then _
  Console.WriteLine(“Is a SuperHero object.”)

SuperHero hero = new SuperHero();

// No “With” construct
hero.Name = “SpamMan”;
hero.PowerLevel = 3;

hero.Defend(“Laura Jones”);
SuperHero.Rest();   // Calling static method

SuperHero hero2 = hero;   // Both refer to same object
hero2.Name = “WormWoman”;
Console.WriteLine(hero.Name);   // Prints WormWoman

hero = null ;   // Free the object

if (hero == null)
  hero = new SuperHero();

Object obj = new SuperHero(); 
if (obj is SuperHero)
  Console.WriteLine(“Is a SuperHero object.”);

Structs

Structure StudentRecord
  Public name As String
  Public gpa As Single

  Public Sub New(ByVal name As String, ByVal gpa As Single)
    Me.name = name
    Me.gpa = gpa
  End Sub
End Structure

Dim stu As StudentRecord = New StudentRecord(“Bob”, 3.5)
Dim stu2 As StudentRecord = stu  

stu2.name = “Sue”
Console.WriteLine(stu.name)    ‘ Prints Bob
Console.WriteLine(stu2.name)  ‘ Prints Sue

struct StudentRecord {
  public string name;
  public float gpa;

  public StudentRecord(string name, float gpa) {
    this.name = name;
    this.gpa = gpa;
  }
}

StudentRecord stu = new StudentRecord(“Bob”, 3.5f);
StudentRecord stu2 = stu;  

stu2.name = “Sue”;
Console.WriteLine(stu.name);    // Prints Bob
Console.WriteLine(stu2.name);   // Prints Sue

Properties

Private _size As Integer

Public Property Size() As Integer
  Get
    Return _size
  End Get
  Set (ByVal Value As Integer)
    If Value < 0 Then
      _size = 0
    Else
      _size = Value
    End If
  End Set
End Property

foo.Size += 1

private int _size;

public int Size {
  get {
    return _size;
  }
  set {
    if (value < 0)
      _size = 0;
    else
      _size = value;
  }
}

foo.Size++;

Delegates / Events

Delegate Sub MsgArrivedEventHandler(ByVal message As String)

Event MsgArrivedEvent As MsgArrivedEventHandler

‘ or to define an event which declares a delegate implicitly
Event MsgArrivedEvent(ByVal message As String)

AddHandler MsgArrivedEvent, AddressOf My_MsgArrivedCallback
‘ Won’t throw an exception if obj is Nothing
RaiseEvent MsgArrivedEvent(“Test message”)
RemoveHandler MsgArrivedEvent, AddressOf My_MsgArrivedCallback

Imports System.Windows.Forms

Dim WithEvents MyButton As Button   ‘ WithEvents can’t be used on local variable
MyButton = New Button

Private Sub MyButton_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyButton.Click
  MessageBox.Show(Me, “Button was clicked”, “Info”, _
    MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub

delegate void MsgArrivedEventHandler(string message);

event MsgArrivedEventHandler MsgArrivedEvent;

// Delegates must be used with events in C#

MsgArrivedEvent += new MsgArrivedEventHandler(My_MsgArrivedEventCallback);
MsgArrivedEvent(“Test message”);    // Throws exception if obj is null
MsgArrivedEvent -= new MsgArrivedEventHandler(My_MsgArrivedEventCallback);

using System.Windows.Forms;

Button MyButton = new Button(); 
MyButton.Click += new System.EventHandler(MyButton_Click);

private void MyButton_Click(object sender, System.EventArgs e) {
  MessageBox.Show(this, “Button was clicked”, “Info”,
    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Console I/O

Special character constants
vbCrLf, vbCr, vbLf, vbNewLine
vbNullString
vbTab
vbBack
vbFormFeed
vbVerticalTab
“”
Chr(65)  ‘ Returns ‘A’

Console.Write(“What’s your name? “)
Dim name As String = Console.ReadLine()
Console.Write(“How old are you? “)
Dim age As Integer = Val(Console.ReadLine())
Console.WriteLine(“{0} is {1} years old.”, name, age) 
‘ or
Console.WriteLine(name & ” is ” & age & ” years old.”)

Dim c As Integer
c = Console.Read()    ‘ Read single char
Console.WriteLine(c)   ‘ Prints 65 if user enters “A”

Escape sequences
\n, \r
\t
\\
\”

Convert.ToChar(65)  // Returns ‘A’ – equivalent to Chr(num) in VB
// or

(char) 65

Console.Write(“What’s your name? “);
string name = Console.ReadLine();
Console.Write(“How old are you? “);
int age = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(“{0} is {1} years old.”, name, age);
// or
Console.WriteLine(name + ” is ” + age + ” years old.”);

int c = Console.Read();  // Read single char
Console.WriteLine(c);    // Prints 65 if user enters “A”

File I/O

Imports System.IO

Dim writer As StreamWriter = File.CreateText(“c:\myfile.txt”)
writer.WriteLine(“Out to file.”)
writer.Close()

Dim reader As StreamReader = File.OpenText(“c:\myfile.txt”)
Dim line As String = reader.ReadLine()
While Not line Is Nothing
  Console.WriteLine(“line=” & line)
  line = reader.ReadLine()
End While
reader.Close()

Dim str As String = “Text data”
Dim num As Integer = 123
Dim binWriter As New BinaryWriter (File.OpenWrite(“c:\myfile.dat”)) 
binWriter.Write(str) 
binWriter.Write(num) 
binWriter.Close()

Dim binReader As New BinaryReader (File.OpenRead(“c:\myfile.dat”))
str = binReader.ReadString()
num = binReader.ReadInt32()
binReader.Close()

using System.IO;

StreamWriter writer = File.CreateText(“c:\\myfile.txt”);
writer.WriteLine(“Out to file.”);
writer.Close();

StreamReader reader = File.OpenText(“c:\\myfile.txt”);
string line = reader.ReadLine();
while (line != null) {
  Console.WriteLine(line);
  line = reader.ReadLine();
}
reader.Close();

string str = “Text data”;
int num = 123;
BinaryWriter binWriter = new BinaryWriter(File.OpenWrite(“c:\\myfile.dat”));
binWriter.Write(str);
binWriter.Write(num);
binWriter.Close();

BinaryReader binReader = new BinaryReader(File.OpenRead(“c:\\myfile.dat”));
str = binReader.ReadString();
num = binReader.ReadInt32();
binReader.Close();

Page last modified: 04/20/2006 16:39:28 01/14/2004 05:34:59
Please send any corrections or comments to fmccown@harding.edu.
Home

C#中使用多線程訪問Winform問題

 

我們在做winform應用的時候,大部分情況下都會碰到使用多線程控制界面上控件信息的問題。然而我們并不能用傳統方法來做這個問題,下面我將詳細的介紹。

首先來看傳統方法:

 

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(ThreadFuntion);
thread.IsBackground = true;
thread.Start();
}
private void ThreadFuntion()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}
}
}

 

運行這段代碼,我們會看到系統拋出一個異常:Cross-thread operation not valid:Control ‘textBox1’ accessed from a thread other than the thread it was created on . 這是因為.net 2.0以后加強了安全機制,不允許在winform中直接跨線程訪問控件的屬性。那么怎么解決這個問題呢,下面提供幾種方案。

第一種方案,我們在Form1_Load()方法中加一句代碼:

 

private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
Thread thread = new Thread(ThreadFuntion);
thread.IsBackground = true;
thread.Start();
}

 

加入這句代碼以后發現程序可以正常運行了。這句代碼就是說在這個類中我們不檢查跨線程的調用是否合法(如果沒有加這句話運行也沒有異常,那么說明系統以及默認的采用了不檢查的方式)。然而,這種方法不可取。我們查看CheckForIllegalCrossThreadCalls 這個屬性的定義,就會發現它是一個static的,也就是說無論我們在項目的什么地方修改了這個值,他就會在全局起作用。而且像這種跨線程訪問是否存在異常,我們通常都會去檢查。如果項目中其他人修改了這個屬性,那么我們的方案就失敗了,我們要采取另外的方案。

下面來看第二種方案,就是使用delegate和invoke來從其他線程中控制控件信息。網上有很多人寫了這種控制方式,然而我看了很多這種帖子,表明上看來是沒有什么問題的,但是實際上并沒有解決這個問題,首先來看網絡上的那種不完善的方式:

 

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);

thread.IsBackground=true;
thread.Start();
}

private void CrossThreadFlush()
{
//將代理綁定到方法
FlushClient fc = new FlushClient(ThreadFuntion);
this.BeginInvoke(fc);//調用代理
}
private void ThreadFuntion()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}
}
}

 

使用這種方式我們可以看到跨線程訪問的異常沒有了。但是新問題出現了,界面沒有響應了。為什么會出現這個問題,我們只是讓新開的線程無限循環刷新,理論上應該不會對主線程產生影響的。其實不然,這種方式其實相當于把這個新開的線程“注入”到了主控制線程中,它取得了主線程的控制。只要這個線程不返回,那么主線程將永遠都無法響應。就算新開的線程中不使用無限循環,使可以返回了。這種方式的使用多線程也失去了它本來的意義。

現在來讓我們看看推薦的解決方案:

 

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
thread.IsBackground = true;
thread.Start();
}

private void CrossThreadFlush()
{
while (true)
{
//將sleep和無限循環放在等待異步的外面
Thread.Sleep(1000);
ThreadFunction();
}
}
private void ThreadFunction()
{
if (this.textBox1.InvokeRequired)//等待異步
{
FlushClient fc = new FlushClient(ThreadFunction);
this.Invoke(fc);//通過代理調用刷新方法
}
else
{
this.textBox1.Text = DateTime.Now.ToString();
}
}
}

 

運行上述代碼,我們可以看到問題已經被解決了,通過等待異步,我們就不會總是持有主線程的控制,這樣就可以在不發生跨線程調用異常的情況下完成多線程對winform多線程控件的控制了。

 

 發佈時間:3/18/2009

 http://www.jlorocks.com/content.aspx?conId=2395

 

【转】.NET中强名及其技巧

 

如果你使用.NET作为开发工具很长时间了,你肯定回会碰到“强名”(strong name)这个概念。这个概念并不意味你的组件命名方式必须类似于MyCompany.Gorilla.Biceps的方式。强名的力量体现在对组件的保护方面,.NET Framework使用强名来标识组件和保护组件使其免遭破坏。在这篇文章中我将说明如何建立强名,以及在.NET中使用强名的技巧。

1. 散列和签名 为了了解强名的工作原理,你必须首先理解密码学方面的两个概念:散列(hashing)和数字签名(digital signatures)。散列是用来为明文(plaintext)信息创建一个唯一的压缩的值。这里的“信息”是一个很广泛的概念,对于组件来说,信息就是它本身。如图1所示,信息作为散列作为散列算法的输入而被处理,对于强名情况,采用SHA1算法。

散列是不可逆的,一旦计算出来,是不可能解密的。但是,散列在比较值方面是非常有用的。如果两个组件生成同样的散列值,你可以认为这两个组件是相同的。相反,通过散列计算出来的值和以前计算的值不一样,说明组件中某个地方被修改了。 因此通过散列值你就可以知道,组件是否被修改或破坏。然而你怎样通过散列值来防止别人对你的组件的修改呢?下面就是我要讲的“数字签名”。 虽然数字签名的具体数学原理很复杂,但是概念很简单。一个数字签名依赖于两个相关的数字:公共秘匙(public key)和私有密匙(private key)。如图2所示,当数据通过公共秘匙加密后,它只能通过私有密匙来解密,反之亦然。

2. 组件的强名 在.NET中共同使用散列和数字签名就能够保护你的组件免遭破坏。其原理如图3所示,首先从组件产生一个散列值,然后这个散列值通过你的私有密匙被加密,然后这个散列值和公共密匙被一起防止在组件中。 
在运行的时候,公共语言运行时(CLR)通过比较散列值验证组件。首先公共的密匙用来解密散列,从当前的组件中计算出一个新的散列。如果它和原来的值吻合,那就通过了验证
那么如果一个组件在签名之后被破坏将会发生什么样的情况呢?显然,在运行时从组件中计算出来的散列值将不会与存储在组件中通过私有密匙加密的散列值吻合,这样公共语言运行时将拒绝加载该组件。 

注意强名只是保证了组件的完整性,而并非它的安全性,没有什么办法来防止某个人创建一个恶意的组件,并通过强名来给它签名。你可以通过强名来验证某个组件在签名后是否被破坏。基于你对于信息的选择。这一切将由你来决定是否相信从某个地方来的组件和代码信息。 

3.强名的其它信息 

除了从组件内容求出来的散列,强名还包含一下三个方面的信息。 

l 组件简单文本名称 

l 组件版本号 

l 组件的语言文化代码 

所有的这些信息,将为每个组件提供唯一的标识。有了这些信息,公共语言运行时可以决定一个组件是否被另一个组件通过引用的方式调用。当你从一个组件引用另一个组件,该组件将存储被调用组件的公共密匙。在运行的时候,公共语言运行时将通过这些来判断该组件是否来自正确的供应商。另外强名中的其它信息用来判断组件是否符合引用的绑定策略(binding policy)的要求。 

4.使用强名的技巧 

.NET Framwork SDK和 Visual Studio.NET为指定强名提供了很多的工具,这是很有意义的,因为通过Visual Studio.NET来创建组件具有更多的选择。在你签名之前你必须创建一对密匙(公共密匙和私有密匙),通常密匙对放置在以.snk结尾的文件中。可以通过强名工具sn.exe来实现。 

sn -k MyKeyFile.snk 
如果你使用命令行编译器(vbc.exe或者csc.exe),你就可以为组件连接器al.exe,指定密匙对。如下面的命令行所示,你可以将存储在MyKeyFile.snk中的密匙对作为MyFile.dll的签名。 

al /out:MyFile.dll MyFile.netmodule /keyfile:MyKeyFile.snk 
如果你使用Visual Studio .NET,你仍然可以通过命令行的方式产生你的密匙对。有了密匙对之后你就可以通过设定在组件信息文件(AssemblyInfo.vb 或者semblyInfo.cs)的【AssemblyKeyFile】属性来把它包含到组件中。例如C#工程,你可以通过该属性包含密匙文件而生成一个签名组件。 

[assembly: AssemblyKeyFile(“..\\..\\MyKeyFile.snk”)] 

从被编译的组件到密匙文件,【AssemblyKeyFile】属性中的文件名必须包含完整的相对路径。 

5.通过延迟签名加密 

保护你的私有密匙是非常重要的,如果某个恶意的人取得了你的密匙,他生成的组件将和你签过名的组件一样。因此,应当把你的密匙设于高度的保密状态,公司里面可能就只有几个人知道。这样以来,又怎么给你的组件签名呢?如果就只有你一个人知道密匙,这样会很繁琐,因为你必须为公司中每个开发者开发出来的每个组件签名。 

很幸运的是.NET为这个问题提供了一个很好的方法:延迟签名。通过延迟签名,你可以在只知道公共密匙的情况下创建和测试组件。只有在组件实际分发给用户时才将私有密钥匙包含到组件。下面是使用延迟签名过程的一些技巧总结: 

1. 从公共/私有密钥匙对中提取公共密匙。为了提取公共密匙,也就是存储公共/私有密匙对,你可以使用强名工具,命令行如下: 

sn.exe -p MyKeyFile.snk MyPublicKeyFile.snk 

2. 将包含公共密匙的文件分发给公司所有的开发者,同时将包含公共/私有密钥匙对的文件安全存放。 

3. 在组件信息文件中包含公共密匙的文件,并注明延迟签名。 

[assembly: AssemblyDelaySign(true)] 
[assembly: AssemblyKeyFile(“..\\..\\MyPublicKeyFile.snk”)] 
如果你使用组件连接工具,而非Visual Studio .NET,你可以使用/delaysign命令行来表明延迟签名。 

4. 如果你把组件保存在全局程序集缓存(GAC)中,应关闭对组件的验证,因为GAC默认验证每个组件的强名。如果组件没有采用私有密钥匙来签名,这个验证将会失败。因此,出于开发和测试的目的你可以输入如下的命名行: 

sn.exe -Vr MyFile.dll 

5. 这样,你就可以在开发和测试的时候很自由的使用组件 

6. 当部署一个延迟签名的组件的时候,你必须通过私有密匙来给它签名。 

sn.exe -R MyFile.dll MyKeyFile.snk 

7. 最后,你必须通知GAC重新开启对组件的验证。命名行如下: 

sn.exe -Vu MyFile.dll 
6.可信任计算(TrsutWorthy Computing) 

你肯定听说过微软的“可信任计算”措施,它包含了有关微软产品的很多安全方面的措施。微软正慢慢的而且必然的朝着一个方向发展,那就是他们将使他们所有的软件产品是默认安全的。如果你知道你在做什么,你就可以降低软件(如Windows Server 2003)的安全级别。虽然降低了安全级别,但太可能使你受到突发事件的攻击。 

当你给你的组件赋予强名,你在做就是“可信任计算”。通过强名来分发你的组件,会使得组件不太可能成为木马和其他攻击计算机黑客程序的载体。.NET Framework和Visual Studio .NET提供的工具保证了你分发组件的完整性。因此我强烈建议你使用这些工具,通过这些工具来使得计算世界变得更安全一点。 

来源:未明 

 

C# 程序如何添加对 COM 组件的引用

1、注册控件

     用 regsvr32 注册控件。注意,在Win7下必须以管理员身份启动cmd,然后才能正确注册控件。

     例:C:\Windows\system32>regsvr32 F:\Workspace\SmartBridgeCulvert\Licence\Libs\NetRy6S.dll

 

2、添加引用 

      项目 右键—>添加引用…(Add Reference …),在出现的对话框中选择COM选项卡,就能看到刚才注册的组建了,选定,OK

 

 

使用WPF提供的数据验证机制

在用户通过WPF对话框窗口提供所需的数据时,对话框负责确保提供的数据有效,原因如下:

  • 从安全角度讲,应验证所有输入。

  • 从特定于域的角度讲,数据验证可防止该代码处理错误的数据,因为这样可能会引发异常。

  • 从用户体验的角度讲,对话框可以通过向用户显示哪些输入数据无效来为用户提供帮助。

  • 从性能角度讲,多层应用程序中的数据验证可以减少客户端和应用程序层之间的往返次数,尤其是在该应用程序由 Web 服务或基于服务器的数据库组成时。

若要验证 WPF 中的绑定控件,您需要定义验证规则,然后将其与该绑定关联。验证规则是派生自 ValidationRule 的自定义类。下面的示例演示验证规则 MarginValidationRule,该规则检查绑定值是否是 Double 以及是否位于指定的范围内。

C#

using System.Globalization;
using System.Windows.Controls;

namespace SDKSample
{
    public class MarginValidationRule : ValidationRule
    {
        double minMargin;
        double maxMargin;

        public double MinMargin
        {
            get { return this.minMargin; }
            set { this.minMargin = value; }
        }

        public double MaxMargin
        {
            get { return this.maxMargin; }
            set { this.maxMargin = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double margin;

            // Is a number?
            if (!double.TryParse((string)value, out margin))
            {
                return new ValidationResult(false, “Not a number.”);
            }

            // Is in range?
            if ((margin < this.minMargin) || (margin > this.maxMargin))
            {
                string msg = string.Format(“Margin must be between {0} and {1}.”, this.minMargin, this.maxMargin);
                return new ValidationResult(false, msg);
            }

            // Number is valid
            return new ValidationResult(true, null);
        }
    }
}

在此代码中,通过重写 Validate 方法来实现验证规则的验证逻辑,该方法对数据进行验证并返回相应的 ValidationResult。

若要将验证规则与绑定控件关联,您需要使用以下标记。

XAML

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>



...


<Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
<TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
  <TextBox.Text>
    <Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <local:MarginValidationRule MinMargin="0" MaxMargin="10" />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>


...


</Window>

对验证规则进行关联之后,WPF 将在数据输入绑定控件时自动应用该规则。如果控件包含无效的数据,则 WPF 将在无效控件周围显示一个红色边框,如下图所示。

untitled

在用户输入有效数据之前,WPF 不会将用户限制于无效的控件。这对于对话框来说是很有利的;无论数据是否有效,用户都应当能够在对话框中自由导航控件。但是,这意味着用户可以输入无效的数据,然后按“确定”按钮。因此,在按“确定”按钮时,您的代码还需要通过处理 Click 事件来验证对话框中的所有控件。

C#

using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

void okButton_Click(object sender, RoutedEventArgs e)
{
    // Don’t accept the dialog box if there is invalid data
    if (!IsValid(this)) return;

        }

        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }

            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {  
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }

            // All dependency objects are valid
            return true;
        }
    }
}

此代码将在窗口上枚举所有依赖项对象。如果有任何一个对象无效(由 GetHasError 返回),则此无效的控件将获得焦点,IsValid 方法将返回 false 并将该窗口视为无效。

一旦对话框有效,则可以安全地关闭并返回。在返回过程中,需要向调用函数返回一个结果。

 

本文来自msdn,一切归msdn所有。

C#中三种截屏方式总结

[转载自:http://www.yqdown.com/chengxukaifa/CC/4012.htm]

昨天写自动化测试的CASE的时候,碰到一个疑难杂症,调用截图的函数去截取一个Popup窗口,但是总是把背景程序给截下来,Popup窗口就跟看不到一样。本来以为是同步的问题,也就是以为先截图再点击弹出Popup窗口了。后来加了N个Thread.Sleep来测试,发觉根本不是因为这个原由,而是截图的函数截不下来这个窗口。

这个为啥呢,只好把截图的函数代码翻出来看,以前是用这种方式的:
BitBlt(dcImage, 0, 0, (int)(rect.Width), (int)(rect.Height), dcScreen, (int)(rect.Left), (int)(rect.Top), TernaryRasterOperations.SRCCOPY);

凭直觉感觉应该是因为这种通过DC的方式对WPF程序支持有问题,但是又觉得奇怪就是截取其它的WPF组件和窗口都没有问题,偏偏Popup窗口不可以。

前些天听说另外一种截屏的要领,这种要领连被遮挡的窗口都可以截,于是就Google一大把,找打了PrintWindow函数,于是就有了第二种处理方案,代码如下:

IntPtr hdc = Native.GetWindowDC(this.Handle);
if (hdc != IntPtr.Zero)
{
    IntPtr hdcMem = Native.CreateCompatibleDC(hdc);
    if (hdcMem != IntPtr.Zero)
    {
        IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, (int)(Rect.Width), (int)(Rect.Height));
        if (hbitmap != IntPtr.Zero)
        {
            Native.SelectObject(hdcMem, hbitmap);
            Native.PrintWindow(this.Handle, hdcMem, 0);

            Native.DeleteObject(hbitmap);
            Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
            bmp.Save(sPath);
       }
        Native.DeleteObject(hdcMem);
    }
    Native.ReleaseDC(this.Handle, hdc);
}

 

就是拿到窗口的句柄,通过PrintWindow API来截取窗口。

但是更让人气愤的事情出现了,截出来的窗口中,只要是用到WPF组件的地点,全部是黑块儿,只有MFC的窗口框架和按钮可以正常被截取。

于是乎,就无奈的继续分析这个问题,我记得WPF是没有走GDI,而是通过Directx渲染的,那就是说DC的方式和PrintWindow的方式都不靠谱,但是截Directx的貌似还比较复杂。

突然想起来,平常报bug的时候都是按PrintScreen,然后再处理一下的,那应该PrintScreen按键是管用的,看来只能曲线救国了。但是那样就得走剪切板了,貌似会破坏剪切板的数据,不过如果我在截取前保存一下数据,在截取后再恢复一下剪切板数据,那就没有问题了。

于是就有了第三种处理方案(暂时还没有加恢复剪切板数据的代码):

const uint KEYEVENTF_EXTENDEDKEY = 0x1;
const uint KEYEVENTF_KEYUP = 0x2;
const byte VK_SNAPSHOT = 0x2C;
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY KEYEVENTF_KEYUP, UIntPtr.Zero);

IDataObject iObj = Clipboard.GetDataObject();
if (iObj.GetDataPresent(DataFormats.Bitmap, true))
{
    Bitmap bmpScreen = iObj.GetData(DataFormats.Bitmap, true) as Bitmap;
    Bitmap bmpOutput = new Bitmap((int)this.Rect.Width, (int)this.Rect.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    Graphics g = Graphics.FromImage(bmpOutput);
    Rectangle destRectangle = new Rectangle(0, 0, (int)this.Rect.Width, (int)this.Rect.Height);
    g.DrawImage(bmpScreen,destRectangle,  (int)this.Rect.X, (int)this.Rect.Y, (int)this.Rect.Width, (int)this.Rect.Height, GraphicsUnit.Pixel);

 

    bmpOutput.Save(sPath, System.Drawing.Imaging.ImageFormat.Bmp);
}

 

测试可用,只好先用着了

不过还有多个问题,先写下来,留待以后处理:

1. 针对第三种方案,既然可以按PrintScreen键截图,那对应的API是什么,总觉得发键盘消息没有直接调API稳定

2. 针对WPF截图有没有更好的处理方案

 

 

 

晒一下c#截屏对象code

 

昨天,因为需要一个截屏的功能所以自己就写了一下。第一版是一个单纯的利用.net类库来实现的屏幕方式。

        static public void PrintSystemScreen (string file) {

            
if (string.IsNullOrEmpty(file)) {
                
// Create a random file name by GUID and set the saved 
                
// directory at current directory.
                file = Guid.NewGuid().ToString();
            }


            
// Create a bitmap for save
            Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                    Screen.PrimaryScreen.Bounds.Height,
                                    PixelFormat.Format32bppPArgb);

            
// Create a graphic for drawing from bmp
            Graphics screenG = Graphics.FromImage(bmp);
            screenG.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                   Screen.PrimaryScreen.Bounds.Y,
                                   
00,
                                   Screen.PrimaryScreen.Bounds.Size,
                                   CopyPixelOperation.SourceCopy);

            ImageParams imgParam 
= new ImageParams(file);
            bmp.Save(imgParam.FilePath, imgParam.CodeInfo, imgParam.EncoderParam);
        }

第二版,我加入了根据给出的应用程序主窗口去截取界面的功能,使用Win32 Api来实现:

    /// <summary>
    
/// GeneralScreen include serval functions.
    
/// Capture single screenshot.
    
/// Capture application screenshot.
    
/// !Capture web page screenshot.
    
/// </summary>

    static public class GeneralScreen {

        
/// <summary>
        
/// Capturing the current screen operation then save
        
/// image to the indicated file.
        
/// </summary>
        
/// <param name=”file”></param>

        static public void PrintSystemScreen (string file) {
            IntPtr screenHandle 
= NativeMethods.GetDesktopWindow();
            Capture(screenHandle, file);
        }


        
/// <summary>
        
/// Create a random file name by GUID under the runtime directory.
        
/// </summary>

        static public void PrintSystemScreen () {
            PrintSystemScreen(
null);
        }


        
/// <summary>
        
/// Capturing the indicated application window operation then save
        
/// image to the indicated file. If the file parameter not set, function will
        
/// create a random file name by GUID under the runtime directory.
        
/// </summary>
        
/// <param name=”handle”>window’s handle</param>
        
/// <param name=”file”>target image file</param>

        static public void PrintApplicationScreen (IntPtr handle, string file) {
            
if (NativeMethods.SetForegroundWindow(handle)) {
                Capture(handle, file);
            }

        }



        
#region Helper

        
/// <summary>
        
/// Capture the indicated region screenshot by the indicated window.
        
/// </summary>
        
/// <param name=”handle”>indicated window handle</param>
        
/// <param name=”file”>save image file name</param>

        static private void Capture (IntPtr handle, string file) {
            
// Testing source handle
            if (handle != IntPtr.Zero) {
                NativeMethods.RECT srcRect;

                
// Get the source window’s information
                if (NativeMethods.GetWindowRect(handle, out srcRect)) {
                    
int width = srcRect.Right  srcRect.Left;
                    
int height = srcRect.Bottom  srcRect.Top;
                    Capture(srcRect.Left, srcRect.Top, width, height, file);
                }

            }

        }



        
/// <summary>
        
/// Capture the screenshot by coordinate from display memory.
        
/// </summary>
        
/// <param name=”x”></param>
        
/// <param name=”y”></param>
        
/// <param name=”width”></param>
        
/// <param name=”height”></param>
        
/// <param name=”file”></param>

        static private void Capture (int x, int y, int width, int height, string file) {
            System.Drawing.Image targetImg;
            IntPtr displayDC 
= IntPtr.Zero;
            IntPtr compatibleDC 
= IntPtr.Zero;
            IntPtr bmp 
= IntPtr.Zero;

            
try {

                displayDC 
= NativeMethods.CreateDC(DISPLAY,
                                                   IntPtr.Zero,
                                                   IntPtr.Zero,
                                                   IntPtr.Zero);
                
if (displayDC == IntPtr.Zero) {
                    
throw new Exception(CreateDC failed!);
                }


                compatibleDC 
= NativeMethods.CreateCompatibleDC(displayDC);
                
if (compatibleDC == IntPtr.Zero) {
                    
throw new Exception(CreateCompatibleDC failed!);
                }


                bmp 
= NativeMethods.CreateCompatibleBitmap(displayDC, width, height);

                
// set DC relate to bmp
                if (NativeMethods.SelectObject(compatibleDC, bmp) == IntPtr.Zero) {
                    
throw new Exception(CreateCompatibleBitmap failed);
                }


                
if (0 == NativeMethods.BitBlt(compatibleDC, 00, width, height,
                                              displayDC, x, y,
                                              
0xcc0020)) {
                    
throw new Exception(BitBlt failed);
                }


                targetImg 
= System.Drawing.Image.FromHbitmap(bmp);

                
// Save image
                
//
                if (string.IsNullOrEmpty(file)) {
                    
// Create a random file name by GUID and set the saved 
                    
// directory at current directory.
                    file = Guid.NewGuid().ToString();
                }


                ImageParams imgParam 
= new ImageParams(file);
                targetImg.Save(imgParam.FilePath, imgParam.CodeInfo, imgParam.EncoderParam);
            }
 finally {
                NativeMethods.DeleteDC(displayDC);
                NativeMethods.DeleteDC(compatibleDC);
                NativeMethods.DeleteObject(bmp);
            }

        }

        
#endregion

    }



    
/// <summary>
    
/// The nativeMethods includes the win32 api for the others 
    
/// class calling.
    
/// </summary>

    internal static class NativeMethods {
        
// Methods
        [DllImport(gdi32.dll, SetLastError = true, ExactSpelling = true)]
        
internal static extern int BitBlt (IntPtr destDC, int xDest, int yDest, int width, int height, IntPtr sourceDC, int xSource, int ySource, uint rasterOperation);
        [DllImport(
gdi32.dll, SetLastError = true, ExactSpelling = true)]
        
internal static extern IntPtr CreateCompatibleBitmap (IntPtr dc, int width, int height);
        [DllImport(
gdi32.dll, SetLastError = true, ExactSpelling = true)]
        
internal static extern IntPtr CreateCompatibleDC (IntPtr dc);
        [DllImport(
gdi32.dll, EntryPoint = CreateDCW, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
        
internal static extern IntPtr CreateDC (string driver, IntPtr device, IntPtr output, IntPtr devMode);
        [DllImport(
gdi32.dll, ExactSpelling = true)]
        
internal static extern int DeleteDC (IntPtr dc);
        [DllImport(
gdi32.dll, ExactSpelling = true)]
        
internal static extern int DeleteObject (IntPtr gdiObject);
        [DllImport(
gdi32.dll, SetLastError = true, ExactSpelling = true)]
        
internal static extern IntPtr SelectObject (IntPtr dc, IntPtr gdi);

        [DllImport(
user32.dll)]
        [
return: MarshalAs(UnmanagedType.Bool)]
        
internal static extern bool GetWindowRect (IntPtr hWnd, out RECT lpRect);
        [StructLayout(LayoutKind.Sequential)]
        
public struct RECT {
            
public int Left;
            
public int Top;
            
public int Right;
            
public int Bottom;
        }


        [DllImport(
user32.dll, ExactSpelling = true, CharSet = CharSet.Auto)]
        [
return: MarshalAs(UnmanagedType.Bool)]
        
internal static extern bool SetForegroundWindow (IntPtr hWnd);

        [DllImport(
user32.dll)]
        
public static extern IntPtr GetDesktopWindow ();
    }

在这里我用了一个辅助的类ImageParam,这个类可以根据给出的文件名自己识别需要生成什么格式的图片文件。
完整的Demo工程从这里下载

C#面试题

下面的题目是我从网上搜集来的一下面试题,我自己写的答案,有什么错误的地方请大家也帮我纠正一下。

1. C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?
property用法
get/set方法。主要用于类与外部程序之间的数据交互使用。增加了对类内部数据访问的安全性和方便性,在编译期就可以进行类型检查和访问权限检查。

attribute用法
[STAThread]
public void Thrd(){…}
attribute是一个派生自System.Attribute基类的类。attribute可在反射中被枚举,查询。(当编译器看到一个属性被附着给一个类型或成员时,它会搜索

具有指定属性名的System.Attribute派生类。如果编译器没有找到匹配的类,它就在指定的属性名后面加上Attribute,然后再进行搜索。因此,常见的使

用做法是将属性类名定义为以Attribute结尾,在使用时忽略名称的这一部分。)使用Attribute可以让用户把自定义的信息附属到实体上,还可以在运行时

动态查询,这些信息不仅可以被用户取出来作为一种类型的标注,它更可以被编译器所识别,作为编译时的一种附属条件参加程序的编译。举例如

[STAThread]和[MTAThread]线程模式属性,通过这两个属性可以指定线程是单线程模式还是多线程模式。(线程模型只影响使用COM interop的应用程

序,将这个属性应用于不使用COM interop的程序将不会产生任何效果。)
几个常用的属性:
AttributeUsage | Class | 指定另一个属性类的有效使用方式
CLSCompliant | 全部 | 指出程序元素是否与CLS兼容
Conditional | Method | 指出如果没有定义相关联的字符串,编译器就可以忽略对这个方法的任何调用
DllImport | Method | 指定包含外部方法的实现的DLL位置
STAThread | Method(Main) | 指出程序的默认线程模型为STA
MTAThread | Method(Main) | 指出程序的默认模型为多线程(MTA)
Obsolete | 除了Assembly、Module、Parameter和Return | 将一个元素标示为不可用,通知用户此元素将被从未来的产品
ParamArray| Parameter |允许单个参数被隐式地当作params(数组)参数对待
Serializable| Class、Struct、enum、delegate |指定这种类型的所有公共和私有字段可以被串行化
NonSerialized |Field| 应用于被标示为可串行化的类的字段,指出这些字段将不可被串行化
StructLayout| Class、struct |指定类或结构的数据布局的性质,比如Auto、Explicit或sequential
ThreadStatic |Field(静态) |实现线程局部存储(TLS)。不能跨多个线程共享给定的静态字段,每个线程拥有这个静态字段的副本

2. 讲一讲你理解的web service,在dot net framework中,怎么很好的结合xml?
我个人理解web service是跨网络提供服务的一项技术的集合,主要通过各种不同的协议来实现一个服务的支持,比如http(Hypertext Transfer Protocol) 协议,xml(eXtensible Markup Language),soap(Simple Object Access Protocol)协议,WSDL (Web Services Description Language),UDDI (Universal Description, Discovery and Integration)。.net framework中提出了xml web service的概念。这个概念主要阐述了,将xml web service作为一个英特网上进行分布式计算的基础构架。开放标准和通信,实现通过人与应用程序的协作,通过xml web service整合应用程序来创建一个平台。应用程序从不同的源中经过xml web service来整合实现。以下是.net关于xml web service的定义:
. xml web service通过一个标准的协议向web用户公布实用功能。大多数情况下这个协议是SOAP协议。
. xml web service通过一种方法去描述接口,这些信息必须足够详细以便用户能根据这些信息去实现一个客户应用程序。这个描述通常是以一个xml文档(Web Services Description Language)呈现。
.一旦xml web service被注册,那么潜在的用户可以很容易的通过Universal Discovery Description and Integration 找到这些服务。

3. C#, Java 和 c++的特点,有什么相同的地方,不同的地方,C#分别从c++和java中吸取了他们那些优点?
(1)语法比较相似
(2)都是面向对象编程语言,C#和Java是纯面向对象,而c++包含多种编程模式。
(3)C#, Java都有垃圾回收机制,而c++的内存释放需要程序员自己控制。
(4)C#, Java都是被编译一种中间语言的模式,然后在运行时由运行环境进行生产机器语言。而c++是直接编译到机器语言。
(5)C#, Java支持类单继承和接口多重继承,而C++支持类多重继承。
(6)C#从java中吸取了垃圾自动回收,类单继承和接口多继承,基于一个运行时环境便于平台移植,
(7)C#,Java没有指针,C++有
(8)C#加强了Java的属性概念,并在编译器进行安全类型检查和访问控制检查。C++没有
(9)C#, Java吸收了C++泛型编程的思想,和接口的思想并使其成为语言的一种特性。
(10)C#还支持对象索引机制。
(11)没有全局变量,都是从一个基类开始,具有自己的类体系结构,没有头文件概念,都是用层次名称空间来控制体系。

4. C#可否对内存进行直接的操作?
可以直接操作,只不过需要一下系统的API,如OpenMapingFile等。由于在托管代码中我们不能使用指针,那么需要使用unsafe标记来声明来使用指针对内存进行操作。如果是关于c#的内存分配问题,这个内容比较长,我将在另一篇文章里进行讨论。

5. 用Visual C++ 6.0编写的代码(unmanaged code),如何在CLR下和其他dot net component结合?
将unmanaged code 编译成dll, 然后通过DllImport属性的方式导入公开的方法到framework.

6. C#中的委托是什么?事件是不是一种委托?
可以把委托看作是经过.net包装的托管指针,使用委托先要定义委托,然后声明委托变量,事件是一种委托。

7. 描述一下C#中索引器的实现过程,是否只能根据数字进行索引?
C#中的索引器是通过一个特殊的属性this[]来实现的,也可以通过其他的类型来进行索引,如字符串。

8. C#中要使一个类支持FOREACH遍历,实现过程怎样?
类要实现IEnumerable接口, 并通过IEnumerable接口的GetEnumerator();返回一个IEnumerator对象。

    class CountryList : IEnumerable {
        
private ArrayList m_list;

        
public CountryList () {
            m_list 
= new ArrayList();
            m_list.Add(
China);
            m_list.Add(
America);
            m_list.Add(
England);
        }


        
public IEnumerator GetEnumerator () {
            
return m_list.GetEnumerator();
        }

    }

9. 你对XMLHTTP、WEBSERVICE 了解吗?简单描述其特点、作用?

XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。

XMLHTTP是AJAX网页开发技术的重要组成部分。

除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。

WebService是由W3C组织定义的“一个软件系统被设计为支持跨网络实现机器到机器共同操作”。WebService经常使用诸如Web APIs来跨网络访问并执行远端系统上的服务。

10. 接口和抽象类有什么区别?你选择使用接口和抽象类的依据是什么?
接口是一个规范和比抽象类约束更强的类,接口不能拥有实体,而抽象类可以有实体。在定义规范的时候使用接口,在设计类体系是使用抽象类。

11. net的错误处理机制是什么
异常处理,通过抛出一个异常,在代码块中使用try… catch … finally关键字来实现异常捕获和处理。.net的所有异常类都是从System.Exception类继承而来。

12. 您了解设计模式么?请列出您所知道的设计模式的名称。
用来在特定环境下解决问题的一个较优方法。
单件模式、桥接模式、工厂模式、抽象工厂模式、构建者模式、适配器模式、观察者模式、组合模式。

13. 什么是Application Pool?
应用程序池是将一个或多个应用程序链接到一个或多个工作进程集合的配置。应用程序池中的应用程序与其他应用程序被工作进程边界分隔,所以某个应用程序池中的应用程序不会受到其他应用程序池中应用程序所产生的问题的影响。

14. Remoting在客户端服务器怎么实现 ?
15. .什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释?
应用程序域是一个.net framework提供的执行托管代码的环境。这个环境是提供了一个隔绝的不可卸载的安全边界。你可以在一个应用程序域里加载装配件或可执行程序。并且一个应用程序域运行出错了,可以卸载掉而不用担心影响其他应用程序域的工作。

托管代码是为面向公共语言运行库的服务编写的代码。

强类型系统是对数据类型有严格的要求和限制,每一个变量和每一个表达式都有类型,在使用一个变量前系统都会进行类型检查。

简单的说装箱就是将值类型转换成引用类型,而拆箱刚好是相反的过程。

重载就是对于同名函数赋予不同的参数列表,以适应同的访问需求:如
void Output(string name) {}
void Output(string name, int start) {}

CTS:公共类型系统.主要是为了语言之间的进行标准化处理.
CLS:公共语言规范.主要是确保代码可以在任何语言中访问的最小标准集体
CLR:公共语言运行时.主要是管理代码..处理,加载代码,以及所有服务的代码

 

Visual Studio 2010 RC版,WPF和WinForm的编辑都非常稳定了,庆祝一下

比起Visual Studio 2010 Beta2,Visual Studio 2010 RC版的WPF和WinForm的编辑都非常稳定了,尤其是WPF,已经比VS2005和2008的编辑器有了质的飞跃,开始爱上它了。

下面是一段摘自网络的片段:

 

WPF 4用建立在新的System.Xaml.dll之上的新的引擎换掉了XamlReader.Load(), BAML 装载, 控件和 数据模板功能的实现。作为其中的一部分工作,修补了许多缺陷,做了很多功能方面的改进。XamlReader.Load()的用户可以利用XAML2009中的若干新的语言特性,例如对泛型类型的支持。MarkupExtensions 和 TypeConverters 现在可以在对象图创建过程中得到更多的服务,能促成更多的场景,例如对Root对象的访问。通过使用System.Xaml.dll提供的许多新的底层API,用于分析和操作XAML的工具也将更加容易创建。
另一个支持WPF-Silverlight连续体的新特性是VisualStateManager(视觉状态管理器),引进了一种简单的新方式来将视觉状态施加给控件。这个机制提供了一种方式,通过提供将控件逻辑映射到各自的起始和终止视觉状态的方法,可以轻易地定制控件的外观(look)和行为(feel)。
WPF 4还提供了XBAP和宿主HTML网页(XBAP在其中是在一个HTML帧或IFRAME元素中装载的)中的脚本间的直接通讯手段。XBAP可以深入访问HTML DOM,包括对内嵌在HTML网页中的任何ActiveX控件的访问,以及对DOM事件的处理。
并且,WPF在过去的版本中还引进了虚拟化的控件(virtualized controls),但从来没有提供一个标准化的方式让一个自动化客户端与一个虚拟化的控件作交互。WPF 4中加了两个控件模式,ItemsContainerPattern 和VirtualizedItemPattern,来支持对虚拟化了的元素的访问和交互。ItemsContainerPattern可用来访问虚拟化的控件以及找到虚拟化的个项(item),而VirtualizedItemPattern则可用于实现虚拟化的个项。

 

Team Foundation Server的安装

一、VSTS安装准备

Team System的安装其实最主要的就是Team Foundation Server的安装了,Beta 2之前的安装纷繁复杂,到了Beta 2之后情况改观很大,一般情况下,如果你在Clear的机器上安装TFS的话,一般都会比较顺利。

TFS的安装有两种模式:单服务器模式以及多服务器模式。因为TFS的逻辑划分可以分为Data Tier以及Application Tier还有Client Tier。

所谓单服务器模式就是DT和AT在同一台机器,而多服务器模式则表示DT/AT分别被部署在两台机器上。

其实,最好的TFS安装指导就是MS提供的,如果你详细按照Install Guide来做,一定可以成功,也就没必要再听我罗嗦了,^_^

如果你还能忍受我在这罗嗦,那就继续看下去吧。

我才用得是多服务器部署模式,需要准备的东西如下:

硬件:两台普通的PC机器,内存都为1G

软件:

1、Windows Share Point Services 2.0 with Service Pack 1 英文版本

2、Windows Server 2003 Enterprise – ENU

3、Microsoft SQL Server 2005 April CTP

这个版本的Yukon是VSTS Beta 2必需的

4、Visual Studio 2005 Team Foundation Server Beta 2 (English)

这个咚咚就是我们安装的重点了

5、Visual Studio 2005 Team Suite Beta 2 (English)

配合TFS的Client端集成开发环境,只有这个版本支持VSTS功能。

首先,安装完毕两台机器,并都Update到最新的补丁。我们命名其中一台机器为GRD-TSDB,作为Data Tier;另外一台为GRD-TSServer,作为Application Tier。

二、Team Foundation Server的安装

1、我们首先来安装Application Tier,也就是活动地点集中在GRD-TSSERVER这台机器上。我们首先需要做的就是在GRD-TSSERVER上安装AD活动目录,并将其设置为主与控制器,DNS解析也使用本机的,并固定此机器的IP地址。

2、在GRD-TSSERVER上建立一个新的域:GRD-TeamSystem。

3、之后需要建立几个帐号以供Data Tier/Application Tier使用,可以使用上面我提到的那份微软的安装指南里面给出的默认帐号:TFSSETUP和TFSSERVICE。这两个帐号是提供给TFS安装以及服务运行所使用的。记录下来这两个帐号的密码。

再建立几个Client需要使用的帐号,这个就随你的心愿了,比如我为Data Tier建立了一个帐号Yukon。

将帐号TFSSETUP / TFSSERVICE加入到Domain Admin安全组内。

注意建立帐号的时候,选择“不能更改密码”以及“密码永不过期”这两个选项。

7、安装IIS,注意,需要将Frontpage扩展禁用掉,启用ASP.NET

8、安装WSS,一路Next即可。最终会自动打开IE访问WSS的系统管理站点,但是往往这个时候就会出现错误,你将WSS的Web.Config的错误提示开关打开就会发现,ASPNET帐号对于目录C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215\Temporary ASP.NET Files没有访问权限,你可以设置相应权限即可。

9、进行到这里就需要首先安装Data Tier层了,因为安装Application Tier的时候需要使用到SQL Server 2005的很多支持。

我们转跳到机器GRD-TSDB上面。Data Tier的安装相对要简单很多。

首先,将GRD-TSDB加入到域GRD-TeamSystem中,使用本机Administrator登陆,将IP选择自动选择,DNS则指定为GRD-TSSERVER的机器IP。

将账号GRD-TeamSystem\Yukon加入到本地系统管理员组内。接着重新启动使用刚才我们建立的那个Yukon帐号登陆到GRD-TeamSystem域中。

10、安装Yukon April CTP版本,选择所有组件,默认一路Next即可。

完成之后,要验证Reporting Service是否可用,使用IE访问

11、安装Data Tier组件,运行Visual Studio 2005 Team Foundation Server Beta 2 (English)安装光盘,选择Install the Team Foundation Databases Tier ONLY,一路Next下去即可。这样如果一切顺利,DT层我们就安装完毕了。

12、接下来我们来AT层。再次转跳到GRD-TSSERVER机器上面,运行Visual Studio 2005 Team Foundation Server Beta 2 (English)光盘,在安装界面里面选择“Install the Team Foundation Application Tier ONLY”,一路Next,其间会提示你输入我们刚才创建的两个帐号,Reboot系统。

 

来自:http://blog.china-b.com/ws2009/Files5/490.html

示例C#利用UdpClient发送广播消息

在此只做收藏被查,原文请访问:http://www.cnblogs.com/cgzwwy/archive/2009/12/10/1621389.html

 

首先写个接受消息的客户端。这里偷了点懒,new UdpClient(11000)就是用Udp方式侦听11000端口,侦听任何发送到11000端口的消息都会接收到。

 

代码

UdpClient udpClient = new UdpClient(11000);
try
{
IPEndPoint RemoteIpEndPoint
= new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes
= udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);

Console.WriteLine(
"This is the message you received " +
returnData.ToString());
Console.WriteLine(
"This message was sent from " +
RemoteIpEndPoint.Address.ToString()
+
" on their port number " +
RemoteIpEndPoint.Port.ToString());

udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}

 

 

 

然后写个发Udp的服务器

 

代码

UdpClient udpClient = new UdpClient(11001);
try
{
udpClient.Connect(IPAddress.Parse(
"192.168.0.255"), 11000);
Byte[] sendBytes
= Encoding.ASCII.GetBytes("Is anybody thereA?");

udpClient.Send(sendBytes, sendBytes.Length);

udpClient.Close();

}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}

 

 

 

其中192.168.0.255是你的内网广播地址,11000是客户端的端口。

广播地址是通过你的子网掩码获得的例如你的网关是192.168.0.1,掩码是255.255.255.0,那么你的广播地址就是192.168.0.255.

 

在C#里调用C++的dll时需要注意的一些问题

2009-11-19 12:21
 
在c#里调用C++的dll,遇到了一些头疼的问题:
 

C++里头文件定义形势如下:

typedef void (*CALLBACKFUN1W)(wchar_t*, void* pArg);
typedef void (*CALLBACKFUN1A)(char*, void* pArg);

bool BIOPRINT_SENSOR_API dllFun1(CALLBACKFUN1 pCallbackFun1, void* pArg);

在其中一个导入的dll方法里,有一个回调函数的参数

[DllImport(“test.dll”, EntryPoint = “dllFunc1”, CharSet = CharSet.Unicode)]
   public static extern bool dllFunc1([MarshalAs(UnmanagedType.FunctionPtr)] CallbackFunc1 pCallbackFunc1 , IntPtr pArg);

回调函数在C#里定义成委托如下:
public delegate void CallbackFunc1(StringBuilder strName, IntPtr pArg);

调试运行,报错。
有时是直接出错退出,信息如下:
Buffer overrun detected!

Program:

A buffer overrun has been detected which has corrupted the program’s internal state. The program cannot safely continue execution and must now be terminated.

有时则能运行起来,但会抛出异常:
System.AccessViolationException: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

几经周折,觅得答案,原来是要指定 调用方式,如下就OK了:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
   public delegate void CallbackFunc1(IntPtr hWnd, IntPtr pArg);

而系统默认方式为 CallingConvention.StdCall。

程序终于不报错了,但是又出现结果不对了
定义成如下时,strName在方法中的值,只有一个字符,
public delegate void CallbackFunc1(StringBuilder strName, IntPtr pArg);

后来改为:
public delegate void CallbackFunc1([MarshalAs(UnmanagedType.LPWStr)] StringBuilder strName, IntPtr pArg);

OK了,strName带出来的值完整了,参数类型定义成 string 或者 StringBuilder 都无所谓

还可以用 IntPtr ,或者 char* 都行(用char* 得加 unsafe)

char* 类型的,得到值后,可循环至’\0’得到整个字符串
IntPtr 类型的,可以用Marshal.Copy出来,如:
Marshal.Copy(IntPtr_source, toBytes, 0, 1024);

如果报
“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”
异常,
还有可能是因为C++和C#的参数类型对应问题,

如:
bool __declspec(dllimport) getImage(unsigned char** ppImage, int& nWidth, int& nHeight);

对应成
[DllImport(“test.dll”)]
public static extern bool getImage(IntPtr ppImage, ref int nWidth, ref int nHeight);

时,
则该方法在调用前,要对传入的ppImage分配空间,如下
IntPtr pImage = Marshal.AllocHGlobal(iWidth * iHeight);
这种方法不推荐,因为是带出结果来,一般这种指针不确定需要分配多大空间的。

正确的要对应成下面这样:
[DllImport(“test.dll”)]
public static extern bool getImage(ref IntPtr ppImage, ref int nWidth, ref int nHeight);

调用时只要定义就行了:
IntPtr pImage = new IntPtr();
int refWidth = 0, refHeight = 0;

getImage(ref pImage, ref refWidth, ref refHeight);

总结,凡是双针指类型参数,可以用 ref IntPtr
而对于 int*, int&, 则都可用 ref int 对应

另外,提一下自定义消息的响应

   public const int WM_USER = 0x0400;
   public const int WM_TEST_MSG = (WM_USER + 0x100);

C# 要响应 dll 的自定义 消息,则要重写 WinForm的DefWndProc方法。

protected override void DefWndProc(ref Message m)

{

switch (m.Msg)
    {

      case WM_TEST_MSG:
      {

       }
      break;

default:
      base.DefWndProc(ref m);
      break;
    }

}

消息发送是通过 Windows 提供的 API 函数 SendMessage 来实现的,它的原型定义:

[DllImport(“User32.dll”,EntryPoint=”SendMessage”)]
private static extern int SendMessage(
       IntPtr hWnd,      // handle to destination window
       uint Msg,         // message
       uint wParam,      // first message parameter
       uint lParam       // second message parameter
);

再转贴一篇相关文章:

C#中调用Windows API的要点

在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的。本文将C#中调用API的要点汇集如下,希望给未在C#中使用过API的朋友一点帮助。另外如果安装了Visual Studio .net的话,在C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Samples\Technologies\Interop\PlatformInvoke\WinAPIs\CS目录下有大量的调用API的例子。
  一、调用格式
  using System.Runtime.InteropServices; //引用此名称空间,简化后面的代码
  …
  //使用DllImportAttribute特性来引入api函数,注意声明的是空方法,即方法体为空。
  [DllImport(“user32.dll”)]
  public static extern ReturnType FunctionName(type arg1,type arg2,…);
  //调用时与调用其他方法并无区别
  可以使用字段进一步说明特性,用逗号隔开,如:
  [ DllImport( “kernel32″, EntryPoint=”GetVersionEx” )]
  DllImportAttribute特性的公共字段如下:
  1、CallingConvention 指示向非托管实现传递方法参数时所用的 CallingConvention 值。
  CallingConvention.Cdecl : 调用方清理堆栈。它使您能够调用具有 varargs 的函数。
  CallingConvention.StdCall : 被调用方清理堆栈。它是从托管代码调用非托管函数的默认约定。
  2、CharSet 控制调用函数的名称版本及指示如何向方法封送 String 参数。
  此字段被设置为 CharSet 值之一。如果 CharSet 字段设置为 Unicode,则所有字符串参数在传递到非托管实现之前都转换成 Unicode 字符。这还导致向 DLL EntryPoint 的名称中追加字母“W”。如果此字段设置为 Ansi,则字符串将转换成 ANSI 字符串,同时向 DLL EntryPoint 的名称中追加字母“A”。
  大多数 Win32 API 使用这种追加“W”或“A”的约定。如果 CharSet 设置为 Auto,则这种转换就是与平台有关的(在 Windows NT 上为 Unicode,在 Windows 98 上为 Ansi)。CharSet 的默认值为 Ansi。CharSet 字段也用于确定将从指定的 DLL 导入哪个版本的函数。
  CharSet.Ansi 和 CharSet.Unicode 的名称匹配规则大不相同。对于 Ansi 来说,如果将 EntryPoint 设置为“MyMethod”且它存在的话,则返回“MyMethod”。如果 DLL 中没有“MyMethod”,但存在“MyMethodA”,则返回“MyMethodA”。
  对于 Unicode 来说则正好相反。如果将 EntryPoint 设置为“MyMethod”且它存在的话,则返回“MyMethodW”。如果 DLL 中不存在“MyMethodW”,但存在“MyMethod”,则返回“MyMethod”。如果使用的是 Auto,则匹配规则与平台有关(在 Windows NT 上为 Unicode,在 Windows 98 上为 Ansi)。如果 ExactSpelling 设置为 true,则只有当 DLL 中存在“MyMethod”时才返回“MyMethod”。
  3、EntryPoint 指示要调用的 DLL 入口点的名称或序号。
  如果你的方法名不想与api函数同名的话,一定要指定此参数,例如:
  [DllImport(“user32.dll”,CharSet=”CharSet.Auto”,EntryPoint=”MessageBox”)]
  public static extern int MsgBox(IntPtr hWnd,string txt,string caption, int type);
  4、ExactSpelling 指示是否应修改非托管 DLL 中的入口点的名称,以与 CharSet 字段中指定的 CharSet 值相对应。如果为 true,则当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Ansi 值时,向方法名称中追加字母 A,当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Unicode 值时,向方法的名称中追加字母 W。此字段的默认值是 false。
  5、PreserveSig 指示托管方法签名不应转换成返回 HRESULT、并且可能有一个对应于返回值的附加 [out, retval] 参数的非托管签名。
  6、SetLastError 指示被调用方在从属性化方法返回之前将调用 Win32 API SetLastError。 true 指示调用方将调用 SetLastError,默认为 false。运行时封送拆收器将调用 GetLastError 并缓存返回的值,以防其被其他 API 调用重写。用户可通过调用 GetLastWin32Error 来检索错误代码。

 

 

[转]使用MVVM模式打造英汉词典

 

     注:  本文为转载,转载必须保留原作者信息及其原始链接!

     原址:http://www.slfans.com/?action-viewnews-itemid-16530

     发布: 2009-6-17 11:26 |  作者: 紫色永恒  

 

最近比较关注MVVM(Model-View_ViewModel)模式,该模式十分适合WPF/Silverlight的开发。出于练习的目的打算使用Silverlight做个英汉词典(可能是由于近来疯狂的听VOA的缘故),下面针对该项目进行简单的分析。
注:由于Silverlight不支持Command 所以并无法像WPF那样完全实现MVVM模式。

老规矩,先看下运行时的截图
image

这里说下我的开发环境

windows server 2008
visual studio 2008 with sp1
sliverlight 2

下面开始一步一步的制作该应用。

首先新建一个Silverlight项目并宿主在ASP.NET Web Application中(当然我强烈建议宿主在ASP.NET MVC中,不过该项目基本上和宿主端没什么联系而并不是每个人都安装了ASP.NET MVC,所以宿主在可以使用Silverlight控件的Web Form中也许受众面更广泛一些)

在Silverlight的项目中分别新建三个文件夹Model、View、ViewModel并添加相应的文件,最终的解决方案视图如下

image

Model/DictModel.cs以及Model/SentModel.cs为纯粹的业务模型,所有的属性都必须实现IPropertyChanged接口以便在其值更改时可以同时更新UI。这两个类同时继承PropertyChangedBase,该基类很简单,请见我的另外一篇文章:让INotifyPropertyChanged的实现更优雅一些

这两个类的代码如下

DictModel.cs

using System;

namespace EternalDict.Model
{
    public class DictModel : PropertyChangedBase
    {
        string _key;
        public string Key
        {
            get
            {
                return _key;
            }
            set
            {
                _key = value;
                this.NotifyPropertyChanged(p => p.Key);
            }
        }

        string _lang;
        public string Lang
        {
            get
            {
                return _lang;
            }
            set
            {
                _lang = value;
                this.NotifyPropertyChanged(p => p.Lang);
            }
        }

        string _audio;
        public string Audio
        {
            get
            {
                return _audio;
            }
            set
            {
                _audio = value;
                this.NotifyPropertyChanged(p => p.Audio);
            }
        }

        string _pron;
        public string Pron
        {
            get
            {
                return _pron == null ? string.Empty : string.Format("[{0}]", _pron);
            }
            set
            {
                _pron = value;
                this.NotifyPropertyChanged(p => p.Pron);
            }
        }

        string _def;
        public string Def
        {
            get
            {
                return _def;
            }
            set
            {
                _def = value;
                this.NotifyPropertyChanged(p => p.Def);
            }
        }

        System.Collections.ObjectModel.ObservableCollection<SentModel> _sentCollection;
        public System.Collections.ObjectModel.ObservableCollection<SentModel> SentCollection
        {
            get
            {
                return _sentCollection;
            }
            set
            {
                _sentCollection = value;
                this.NotifyPropertyChanged(p => p.SentCollection);
            }
        }

    }
}

SentModel.cs

using System;

namespace EternalDict.Model
{
    public class SentModel : PropertyChangedBase
    {
        string _orig;
        public string Orig
        {
            get
            {
                return _orig;
            }
            set
            {
                _orig = value;
                this.NotifyPropertyChanged(p => p.Orig);
            }
        }

        string _trans;
        public string Trans
        {
            get
            {
                return _trans;
            }
            set
            {
                _trans = value;
                this.NotifyPropertyChanged(p => p.Trans);
            }
        }
    }
}

ViewModel/DictViewModel.cs则用来为View/DictView.xmal提供数据

这里我使用海词http://dict.cn/提供的API,通过Linq to XML进行解析。不过有个问题,海词的API可以提供GBK和UTF8这两种编码的服务,不过当前UTF8并不提供汉英翻译的功能,而silverlight并不支持GBK的编码转换,所以也只能实现英汉查找。也许某天你会发现汉英查找可用了,那么八成是海词官方升级了API。

该类的代码如下

using System;
using System.Net;
using System.Xml.Linq;
using System.Linq;
using System.Text;
using EternalDict.Model;

namespace EternalDict.ViewModel
{
    public class DictViewModel
    {
        string _wordToQuery;
        public DictModel Dm { get { return _dm; } set { _dm = value; } }
        private DictModel _dm;

        public DictViewModel()
        {
            _dm = new DictModel();
        }

        public void QueryWord(string wordToQuery)
        {
            this._wordToQuery = wordToQuery;
            string apiUrlString = string.Format("http://api.dict.cn/ws.php?utf8=true&q={0}", this._wordToQuery);
            Uri endPoint = new Uri(apiUrlString);
            WebClient client = new WebClient();
            client.DownloadStringAsync(endPoint);
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
        }

        void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                this.ParseXml(e.Result);
            }
        }

        void ParseXml(string stringToParse)
        {
            /*Silverlight不支持其他编码 囧
            Encoding gbk = Encoding.GetEncoding("GBK");
            Encoding utf8 = Encoding.UTF8;
            byte[] gbkBytes = gbk.GetBytes(stringToParse);
            byte[] utf8Bytes = Encoding.Convert(gbk, utf8, gbkBytes);
            char[] utf8Chars = new char[utf8.GetCharCount(utf8Bytes, 0, utf8Bytes.Length)];
            utf8.GetChars(utf8Bytes, 0, utf8Bytes.Length, utf8Chars, 0);
            stringToParse = new string(utf8Chars);
            */

            XDocument xDoc = XDocument.Parse(stringToParse);
            var nodeDict = xDoc.Root;
            var audio = nodeDict.Elements().Where(p => p.Name == "audio").SingleOrDefault();
            var lang = nodeDict.Elements().Where(p => p.Name == "lang").SingleOrDefault();
            var pron = nodeDict.Elements().Where(p => p.Name == "pron").SingleOrDefault();
            var def = nodeDict.Element("def").Value;
            _dm.Audio = audio == null ? string.Empty : audio.Value;
            _dm.Def = def.Equals("Not Found") ? "未找到该单词的释义" : def;
            _dm.Key = this._wordToQuery;
            _dm.Lang = lang == null ? string.Empty : lang.Value;
            _dm.Pron = pron == null ? "无" : pron.Value;
            var eleSents = nodeDict.Elements().Where(p => p.Name == "sent");
            if (eleSents != null)
            {
                _dm.SentCollection = new System.Collections.ObjectModel.ObservableCollection<SentModel>();
                foreach (var item in eleSents)
                {
                    SentModel sm = new SentModel();
                    sm.Orig = item.Element("orig").Value;
                    sm.Trans = item.Element("trans").Value;
                    _dm.SentCollection.Add(sm);
                }
            }
        }
    }
}

这里公开了DictModel这个属性,用于为View提供数据。在View中完全通过数据绑定与其通讯。现在看下DictView.cs中最重要的几行代码

        DictViewModel dvm = new DictViewModel();
        public DictView()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(Dict_Loaded);
        }
        
        void Dict_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = dvm;
        }

在View加载后便将ViewModel本身作为其DataContext。当点击查询按钮的时候便调用DictViewModel的QueryWord方法。

        private void btnLookUp_Click(object sender, RoutedEventArgs e)
        {
            dvm.QueryWord(txtWord.Text.Trim());
        }

剩下的就是在DictView.xaml中进行UI的设计了,代码比较多就不贴了。比较关键的是

<StackPanel DataContext="{Binding Dm}" Orientation="Vertical" >

这里将BM绑定到该StackPanel的DataContext上,其可视化树上的所有子孙元素便都可以通过Binding与Model进行关联了。

源码下载:点此下载

 

 

[转]如何禁用WPF窗口的系统菜单(SystemMenu)

[WPF疑难]如何禁用WPF窗口的系统菜单(SystemMenu)

                                      周银辉

点击窗口左上角图标时弹出来的菜单也就是这里所说的系统菜单(SystemMenu),有时需要禁用(移除)其中的某些或全部菜单项。刚才也有网友问到了这一点,OK,贴代码:

要全部禁用(移除)菜单项请调用SystemMenuManager.RemoveWindowSystemMenu(Window window)方法,想部分禁用(移除)菜单项则调用SystemMenuManager.RemoveWindowSystemMenuItem(Window window, int itemIndex)方法。
值得注意的是禁用了其中的菜单项那么与之相关联的功能也会被禁用,比如将“关闭”从其中移除,那么窗口的右上角的关闭按钮也会被禁用,在任务栏的窗口图标上右击也不会出现相应的项目

public static class SystemMenuManager
    {
        [DllImport(“user32.dll”, EntryPoint = “GetSystemMenu”)]
        private static extern IntPtr GetSystemMenu(IntPtr hwnd, int revert);
        [DllImport(“user32.dll”, EntryPoint = “GetMenuItemCount”)]
        private static extern int GetMenuItemCount(IntPtr hmenu);
        [DllImport(“user32.dll”, EntryPoint = “RemoveMenu”)]
        private static extern int RemoveMenu(IntPtr hmenu, int npos, int wflags);
        [DllImport(“user32.dll”, EntryPoint = “DrawMenuBar”)]
        private static extern int DrawMenuBar(IntPtr hwnd);
        private const int MF_BYPOSITION = 0x0400;
        private const int MF_DISABLED = 0x0002;
        public static void RemoveWindowSystemMenu(Window window)
        {
            if(window == null)
            {
                return;
            }
            window.SourceInitialized += window_SourceInitialized;
        }
        static void window_SourceInitialized(object sender, EventArgs e)
        {
            var window = (Window) sender;
            var helper = new WindowInteropHelper(window);
            IntPtr windowHandle = helper.Handle; //Get the handle of this window
            IntPtr hmenu = GetSystemMenu(windowHandle, 0);
            int cnt = GetMenuItemCount(hmenu);
            for (int i = cnt – 1; i >= 0; i–)
            {
                RemoveMenu(hmenu, i, MF_DISABLED | MF_BYPOSITION);
            }
        }
        public static void RemoveWindowSystemMenuItem(Window window, int itemIndex)
        {
            if (window == null)
            {
                return;
            }
            window.SourceInitialized += delegate
                                            {
                                                var helper = new WindowInteropHelper(window);
                                                IntPtr windowHandle = helper.Handle; //Get the handle of this window
                                                IntPtr hmenu = GetSystemMenu(windowHandle, 0);
                                                //remove the menu item
                                                RemoveMenu(hmenu, itemIndex, MF_DISABLED | MF_BYPOSITION);
                                                DrawMenuBar(windowHandle); //Redraw the menu bar
                                            };
        }
    }

 

注:

转载必须保留原作者信息和本文原始链接

本文原始链接:http://www.cnblogs.com/zhouyinhui/archive/2008/11/04/1326514.html

[转]浅谈MVP与Model-View-ViewModel(MVVM)设计模式

原文:http://it.crfly.com/read.php?tid=454840&uid=7566

微软的WPF带来了新的技术体验,如Sliverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架
的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性揉合进去
,以应对客户日益复杂的需求变化。
      WPF的数据绑定与Presentation Model相集合是非常好的做法,使得开发人员可以将View和逻辑分离出来,但这种数据绑定技术非常简单实用,也是WPF所特有
的,所以我们又称之为Model-View-ViewModel (MVVM)。这种模式跟经典的MVP(Model-View-Presenter)模式很相似,除了你需要一个为View量身定制的
model,这个model就是ViewModel。ViewModel包含所有由UI特定的接口和属性,并由一个 ViewModel 的视图的绑定属性,并可获得二者之间的松散耦合,所以
需要在ViewModel 直接更新视图中编写相应代码。数据绑定系统还支持提供了标准化的方式传输到视图的验证错误的输入的验证。
如下图MVP设计模式架构所示。

        在视图(View)部分,通常也就是一个Aspx页面。在以前设计模式中由于没有清晰的职责划分,UI 层经常成为逻辑层的全能代理,而后者实际上属于应用
程序的其他层。MVP 里的M 其实和MVC里的M是一个,都是封装了核心数据、逻辑和功能的计算关系的模型,而V是视图(窗体),P就是封装了窗体中的所有操
作、响应用户的输入输出、事件等,与MVC里的C差不多,区别是MVC是系统级架构的,而MVP是用在某个特定页面上的,也就是说MVP的灵活性要远远大于MVC
,实现起来也极为简单。
      我们再从IView这个interface层来解析,它可以帮助我们把各类UI与逻辑层解耦,同时可以从UI层进入自动化测试自动化测试(Unit/Automatic Test)并提
供了入口,在以前可以由WinForm/Web Form/MFC等编写的UI是通过事件Windows消息与IView层沟通的。WPF与IView层的沟通,最佳的手段是使用Binding
,当然,也可以使用事件;Presenter层要实现IView,多态机制可以保证运行时UI层显示恰当的数据。比如Binding,在程序中,你可能看到Binding的Source是
某个interface类型的变量,实际上,这个interface变量引用着的对象才是真正的数据源。
      MVC模式大家都已经非常熟悉了,在这里我就不赘述,这些模式也是依次进化而形成MVC—>MVP—>MVVM。有一句话说的好:当物体受到接力的时候,凡是有
界面的地方就是最容易被撕下来的地方。因此,IView作为公共视图接口约束(契约)的一层意思;View则能传达解耦的一层意思。
下面介绍一下MVVM设计模式。因为WPF技术出现,从而使MVP设计模式有所改进,MVVM 模式便是使用的是数据绑定基础架构。它们可以轻松构建UI的必要元素。
如,下图所示MVVM架构图。

      可以参考The Composite Application Guidance for WPF(prism),prism V2下载源码
      View绑定到ViewModel,然后执行一些命令在向它请求一个动作。而反过来,ViewModel跟Model通讯,告诉它更新来响应UI。这样便使得为应用构建UI非常
的容易。往一个应用程序上贴一个界面越容易,外观设计师就越容易使用Blend来创建一个漂亮的界面。同时,当UI和功能越来越松耦合的时候,功能的可测试性就
越来越强。
      在MVP模式中,为了让UI层能够从逻辑层上分离下来,设计师们在UI层与逻辑层之间加了一层interface。无论是UI开发人员还是数据开发人员,都要尊重这个
契约、按照它进行设计和开发。这样,理想状态下无论是Web UI还是Window UI就都可以使用同一套数据逻辑了。借鉴MVP的IView层,养成习惯。View Model听
起来比Presenter要贴切得多;会把一些跟事件、命令相关的东西放在Controler里。
      参考示例:PersonViewModel层
public FamilyTreeViewModel(Person rootPerson)
{
    _rootPerson = new PersonViewModel(rootPerson);
    _firstGeneration = new ReadOnlyCollection<PersonViewModel>(
new PersonViewModel[]
        {
            _rootPerson
        });
    _searchCommand = new SearchFamilyTreeCommand(this);
}
在这里我不在赘述,详细应用实例参考:
Simplifying the WPF TreeView by Using the ViewModel Pattern
源码下载

WPF中MVVM模式原理分析与实践

        周银辉

2009年07月24日

原文:http://tech.ddvip.com/2009-07/1248427254126248.html

 

 “设计模式”这样的话题似乎快被园子里的兄弟们写透了, 从简单的工厂到 MVC, MVP.  而关于MVVM似乎谈论得相对少些, 今天简单地说说. 值得声明的是: 这里仅仅谈论得是自己对别人发明的东西的一些理解, 可能有所偏误, 望理解. 另外, 搜索了一下,园子里 “clingingboy” 和 “高阳“大哥也谈到了这个模式, 大家不妨参考一下.
在阅读以下内容以前,建议你对这些内容有所了解: WPF, MVC, MVP, MVVM. 关于MVVM语法层面的内容请参考这里: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

1, 前提
可以说MVVM是专为WPF打造的模式, 也可以说MVVM仅仅是MVC的一个变种, 但无论如何, 就实践而言, 如果你或你的团队没有使用”Binding”的习惯, 那么研究MVVM就没有多大意义.
另外,个人觉得, 使用Command以及打造一种合理的简化的方式去使用Command也与使用Binding一样重要.

2, 诞生
为了解决现实世界中的问题,我们需要将现实世界中的事物加以抽象, 然后得到了Domain Object, 无论贫血的还是富血的, 我们都可以简单地把他们归结为”由现实世界抽象出来的模型”, 也就是我们的model, 也就M-V-VM中的”M”.
但其无法与我们的用户进行交互, 所以, 我们需要为其创建一个界面(视图, View), 该视图可以与用户输入设备进行交互, 这很棒, 但问题是如何将View与我们的model关联起来? Binding便可以发挥作用了, 比如视图上的某一个文本框中的文本和Model中的”用户名”关联起来, 用户便可以通过操作该文本框来访问和修改Model的”用户名”了.
这是极其简单的情况, 但实际编程时我们发现, Model中的属性(与方法)往往不那么容易与View中的界面控件关联起来, 比如, “类型不匹配”: 界面控件所需要的类型与模型中属性提高的类型不匹配. “需要额外操作”: 模型中的数据需要经过一些额外的处理才能传给视图,反之亦然.  此时, 我们意识到View似乎需要一个”Helper”类来处理一些额外工作.
这个helper所包含的代码可以放在除了Model外的很多地方(我们现在不考虑贫血富血之类的争论), 比如View中, 记得自己刚学习窗体程序开发时就是这么干的, 将绝大多数处理逻辑放在那个所谓的CodeBehind中. 后来,正如大家在各种设计模式书籍中所看到的一样,为了将View和Model剥离开来,实现view可替换(比如你可以讲自己精心设计的软件同时运行于窗体程序,Web甚至Mobile上), 便有了MVC. 有了MVC以后似乎就开始滋生M-V-XXX之类的争论与变种模型, 比如MVP以及这里的MVVM,甚至MVP也有着Supervising Controller与Presentation Model两种方式. 但主要围绕两个问题,一是model与view之间的关系, 完全隔离的?单向的还是双向的? 二是这个”XXX”需要完成哪些功能,简单流程调度?复杂规则处理? OK,这些争论都没有关系, 是否采用某种模式取决于你的开发所处的环境(比如语言特性,框架特性)以及你的业务特性以及所面临的主要变化点等等.
但与MVC,MVP所不同的是,MVVM的引入不仅仅是技术上的原因(解除耦合应对变化等老生常谈),另外一个很大原因是:软件团队开发方式的改变.如果你做过一段时间的WPF项目开发的话,你可能会有比较明显的感觉:在View层打造上,如何分配程序员和美工的工作.在继续阅读之前,大家可以看看我以前的一篇文章”在UI Designer与Developer之间“. 以前我们团队采用的便是”集成模式”, 我便兼职了其中的”Integrator“角色.这还不错.但说实在的,这仅仅是一个在特殊情况下不得已而为之的暂时方案,所以我们付出了很大的努力开始转向”收割模式”了,要转向这个模式,至少需要两个基本条件:
(1)你拥有能够熟练运用Blend等工具能为程序员输出XAML的美工, 他专注于纯粹的UI/UE, 另外他还必须具有一定的”程序员”思维.以便输出的东西能很好地作为程序的一部分而运转起来,而不是仅仅”看上去”是那样的.
(2)你需要能够脱离View层但仍能编写出高质量代码的程序员.
幸运的是, 我们在努力创造条件1,并取得了很好的效果.(你可以招一个具有Flash脚本编写经验的并且有极大的学习热情的美工人员, 并对他进行Blend的相关培训). 而MVVM模式为我们实现第二个条件提供了极大的便利. 为什么MVC/MVP模式不行而MVVM可以呢? 很简单, 在MVC和MVP模式中, View层都具有很多代码逻辑, 开发View层的是程序员, 虽然UI/UE团队会做很多工作, 但这个层的”实现者”仍然是程序员. 在以前的开发中,其工作得很好, 而在WPF开发中程序员对View层的展现显得力不从心了,美工(指符合上面条件1的美工)虽然很擅长, 但他会说”可惜我不会程序”.于是, 我们需要一种方式将View层的代码逻辑抽取出来,并View层很纯粹以便完全让美工去打造它.相应地, 需要将View层的相应逻辑抽取到一个代码层上,以便让程序员专注在这里.
回想一下, 我们只所以要在View(Xaml)背后写一些代码(C#), 无非是想传递一些数据以及传递数据时的数据的处理或在用户与界面控件进行交互时执行一些操作, 最简单的例子是在MVC中当界面发生交互时View去调用Controler中的某个方法, 以便将该操作的相应”指示”传递到”后台”去. 在以前的技术中, 这样的”衔接性”的代码是必须的. 而在WPF中, 则可以通过另外的技术来进行层与层之间的”衔接”, 这就是”Binding” 和”Command”, 以及稍后我们会提到的”AttachBehavior”. 通过Binding, 我们可以实现数据的传递; 通过Command, 我们可以实现操作的调用.(AttachBehavior的作用稍后再谈). Binding和Command是可以写在XAML中的, 这样看来XAML后面对于的CS文件可以被完全抛弃或不予理会了. 这样的XAML文件正是美工所需要的. 而这些对于Binding以及Command的定义描述以及其他相关信息的代码应该放在那里呢, 当然不是View, 更不是Model, 是”ViewModel”. ViewModel是为这个View所量身定制的, 它包含了Binding是所需的相关信息,比如Converter以及为View的Binding提供DataContext, 它包含了Command的定义以便View层可以直接使用, 另外,它还是一个变种的Controler, 它得负责业务流程的调度.
于是, 便有了这副图, 然后, 正如”时势造英雄”所言, MVVM就诞生了.

3, ViewModel 与 单元测试
如果你是一名正在使用MVVM模式打造软件的程序员, 那么我劝你尽快忘掉View. 你所面对的是这样一个模式”UnitTest-ViewModel-Model”(这并非一个模式, 仅仅是我为阐述观点而暂时如此表述的).
记得曾经有一个Model-View-AbstractView模式, 而MVVM中的VM实际也是一个AbstractView: the abstraction of view. 它是一个抽象的View, 具有一个View的灵魂,而不具备相应的可视化控件而已. 所以对于程序员而已, 打造这样一个抽象的VM就可以认为是完成View层的打造了.而当美工完成无数控件组成的实际的View后, 我们就可以用Binding和Command这样的黏合剂将这个抽象的View和实际的View黏合在一起了.
那么在黏合之前, 我们怎么知道自己的VM是否正常工作呢? 单元测试!
在说明对于ViewModel进行单元测试的重要性之前, 送给大家一句话: “View and Unit Test are just two different types of ViewModel consumers” (Josh Smith). 如果我们将ViewModel看作生产者, 那么View和Unit Test都是具有同等地位的消费者而已. 并且UnitTest相比于View而言具备更大的消费能力. 或者你可以简单的认为View也仅仅是一种不太推荐的测试方式而已. 所以要实施好这个模式, 那么对ViewModel的单元测试就是必须的了,并且这个测试要不依赖于任何UI控件. (那么不是不对应ViewModel的开发是不是就应该通过测试来驱动了?TDD?)

4, AttachBehavior
一般情况下利用Command, Binding, AttachProperty等WPF特性, View和ViewModel之间能配合工作得很好.  假设我们有一个Button, 当该Button被点击的时候我们要完成一些操作, 很简单, 将该操作封装成一个Command并绑定到该Button上就可以了, 但如果我们要在Button被Load的时候执行另外一些操作呢?  由于Button没有直接被Load事件所触发的Command, 所以不能使用Command了. 不能直接将Load事件处理器写在Button所在的Xaml所对应的CS文件里, 这和我们刚才对MVVM的设计是相矛盾的. 一个不太好的方案是继承一下Button, 并撰写一个由Load所触发的Command, 这可行, 但明显不好. 正如一个控件没有某个属性并且在不继承的情况下而采用AttachProperty一样, 我们可以采用AttachBehavior. AttachBehavior不是WPF特性, 它仅仅是一个最佳实践, 一个Pattern. 关于AttachBehavior语法如何书写, 请参考 : http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx