2011年10月31日 星期一

特殊符號的英文

from http://tw.knowledge.yahoo.com/question/question?qid=1606121207007

特殊符號的英文

~ Tilde (取代符號)
@ At sign, at (At 符號,At)
# Pound sign (井字號)
$ Dollar sign (錢符號)
^ Caret (插入號)
& Ampersand (And 符號)
* Asterisk (星號)
Backslash (反斜線)
[ Open bracket (左開式方括弧)
] Close bracket (右關式方括弧)
( Open parenthesis (左開式圓括號)
) Close parenthesis (右關式圓括號)
: Colon (冒號)
, Comma (逗號)
-- Double dash (雙破折號)
... Ellipsis (省略符號)
' Single quote (單引號)
" Quote (引號)
= Equals (等號)
+ Plus, plus sign (加,加號)
! Exclamation point (驚歎號)
> Greater than (大於)
< Less than (小於)
? Question mark (問號)
. Period, dot (句號,點)
; Semicolon (分號)
- Hyphen (連字號)
— Dash (破折號)
_ Underscore (底線)
| Vertical bar (垂直線)
{ Open brace (左開式大括號)
} Close brace (右關式大括號)
% Percent, percent sign (百分比,百分比符號)
/ Slash (斜線)
// Double slash (雙斜線)

2011年10月14日 星期五

WPF 中如何 Binding 到 UserControl

WPF 中,最好用的莫過於強大的繫結(Binding)能力了。也因此,以往常用的 WinForm 寫作方式也必須作個改變。這裡以 UserControl 的 Binding 為例。

Windows Form 中 UserControl

第一個例子是舊習慣的 UserControl 寫作方式。

首先有個 MyUserControl,功能為:使用 Count propery,顯示出多個人名的下拉選單,讓使用者選擇。並以 SelectedName 作為選擇項目的輸出。

public partial class MyUserControl : UserControl
  {
    public MyUserControl() { InitializeComponent(); }

    public int Count { get; set; }

    public string SelectedName
    {
      get { return cbNames.SelectedValue as string; }
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
      var q = from i in Enumerable.Range(1, Count)
              select string.Format("Name{0}", i);
      cbNames.ItemsSource = q;
    }
  }

使用此 UserControl 時,只需要在 xaml 中加上 Count 的屬性,就可以顯示多個人名。

MainWindow.xaml

<Window x:Class="NormalUserControl.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:NormalUserControl">
  <Grid>
    <my:MyUserControl HorizontalAlignment="Left" Margin="13,11,0,0" x:Name="myUserControl1" VerticalAlignment="Top" Count="3" />
    <Button Content="Ok" Height="23" HorizontalAlignment="Left" Margin="25,87,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
  </Grid>
</Window>

最後,在 Button Click event handler 中,如下的使用方式,可以知道使用者選擇了何人。
private void button1_Click(object sender, RoutedEventArgs e)
{
  MessageBox.Show(myUserControl1.SelectedName);
}

一切似乎運作的很好。這也是 Windows Form 的寫作方式。

有個問題來了,如果這個 UserControl 的 Count 值,是繫結自另一個控制項呢?

如下:

<Window x:Class="NormalUserControl.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:NormalUserControl">
  <Grid>
    <my:MyUserControl HorizontalAlignment="Left" Margin="13,11,0,0" x:Name="myUserControl1" VerticalAlignment="Top" Count="{Binding}" />
    <Button Content="Ok" Height="23" HorizontalAlignment="Left" Margin="23,108,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    <TextBox x:Name="txtCount" Margin="160,12,247,265" Text="3" />
  </Grid>
</Window>
我們想到將 Count 的值繫結自一個 txtCount 的 TextBox,然而 Visual Studio IDE 卻告訴我,A 'Binding' cannot be set on the 'Count' property of type 'MyUserControl'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject. image

WPF : Binding 到 Control

在 WPF 中,DependencyObject 的屬性如果要被繫結的話,該屬性必須是 DependencyProperty.

修改的方式也不難。首先在MyUserControl.xaml.cs 中使用 dependencyProperty 的 snippet,作一個 Count 的 dependencyProperty, 取代原先的 Count property

image

public static readonly DependencyProperty CountProperty =
  DependencyProperty.Register("Count", typeof(int), typeof(MyUserControl), new PropertyMetadata(default(int))
  );

public int Count
{
  get { return (int)GetValue(CountProperty); }
  set { SetValue(CountProperty, value); }
}

再執行一次,程式可以正常編譯了。

PropertyChangedCallback

執行程式,修改 TextBox為另一個數字後發現,Binding 只有第一次執行時才會繫結,其他時間都不會。為什麼?

原因是目前的實作,並沒有告訴它「當資料變化時該怎麼執行」。

以下是修改後的結果。

public static readonly DependencyProperty CountProperty =
  DependencyProperty.Register("Count", typeof(int), typeof(MyUserControl), 
  new UIPropertyMetadata(default(int), OnCountChanged));

private static void OnCountChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
  var count = (int)e.NewValue;
  var q = from i in Enumerable.Range(1, count)
          select string.Format("Name{0}", i);
  var userControl = o as MyUserControl;
  var comboBox = userControl.FindName("cbNames") as ComboBox;
  comboBox.ItemsSource = q;
}

以上的重點在於,註冊 DependencyProperty 時,告訴 WPF,當 Count 的值有變化時,請執行 OnCountChanged.

UserControl 輸出的 Binding

上面談完了將值 Binding 到 UserControl,UserControl 可以讀值,並顯示 UI。那輸出的值是否也可以 Binding 呢?如下面的程式,我們發現 UserControl 的SelectedName 雖然可以讀出,但也不能做 DataBinding。

<Window x:Class="NormalUserControl.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:NormalUserControl">
  <Grid>
    <my:MyUserControl HorizontalAlignment="Left" Margin="13,11,0,0" x:Name="myUserControl1" VerticalAlignment="Top" Count="{Binding ElementName=txtCount, Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <Button Content="Ok" Height="23" HorizontalAlignment="Left" Margin="23,108,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    <TextBox x:Name="txtCount" Margin="160,12,247,265" Text="4" />
    <Label Content="{Binding SelectedName, ElementName=myUserControl1}" Height="28" HorizontalAlignment="Right" Margin="0,101,247,0" Name="label1" VerticalAlignment="Top" />
    <Label Content="Your Select" Height="28" HorizontalAlignment="Left" Margin="150,101,0,0" Name="label2" VerticalAlignment="Top" />
  </Grid>
</Window>

此時,要解這個問題,SelectedName仍然需要 dependencyproperty。

public string SelectedName
{
  get { return (string)GetValue(SelectedNameProperty); }
  set { SetValue(SelectedNameProperty, value); }
}

public static readonly DependencyProperty SelectedNameProperty =
    DependencyProperty.Register("SelectedName", typeof(string), typeof(MyUserControl),
    new UIPropertyMetadata(null));

 

光這樣是不夠的。ComboBox 的 SelectedItem 並不會自動更新這我們剛剛加上的 SelectedName。

此時在建構子上加如下的繫結(只不過是用程式加的)

var binding = new Binding("SelectedName") { Source = this };
  cbNames.SetBinding(ComboBox.SelectedItemProperty, binding);

 

結論

當 UserControl 遇到 Binding 時,會發生許多原先在 Windows Form 上遇不到的事。正因為 WPF 的繫結非常強大,要駕馭它也要相當的功夫。

2011年9月29日 星期四

Windows 8 的複製檔案

windows 8 在複製檔案時,資訊豐富多了。

image

並且,可以暫停動作。這樣一來,可以讓其他重要的複製先完成。

好想把這個功能放到 Windows 7 哦。

2011年8月18日 星期四

在 Windows 7 上開發 Windows Mobile 6.1 安裝步驟

最近因專案的緣故,需要開發 Windows Mobile 6.1 的應用程式。

這是我第一個 Mobile 的應用程式,沒想到必須使用舊的系統來開發。(心聲:真的有點老舊的系統,好想直接開發 WM 7,就可以使用 Silverlight 了)

無論如何,Visual Studio 2010 是無法開發這麼老舊的系統了。因此必須回頭灌 VS2008,沒想到,過程有點辛苦。

首先,我用了 Hyper-V 上的虛擬機 (Windows 2003)來開發,沒想到 Windows Mobile Emulator 無法模擬 PDA 上的網路。想了一下,在虛擬機上再虛擬一個網路,果然有些不對勁。

以下,是我在實體機(Windows 7)上的安裝步驟。

  1. 安裝 Visual Studio 2008
  2. 安裝 Team Explorer 2008
  3. 安裝 Visual Studio 2008 Service Pack 1
  4. 安裝 VSTS 2008 相容 2010 套件(2~4 的步驟是為了使用 TFS 2010 )
  5. 安裝 drvupdate-amd64.exe (Windows Mobile Device Center for Vista)
  6. 安裝 Windows Mobile 6 Professional SDK Refresh.msi
  7. 安裝 Windows Mobile 6 Professional Images (CHT).msi
  8. 由於我已經安裝了 Windows Virtual PC,而VS2008 上的PDA需要安裝舊版的 Virual PC 2007。為了解決兩個版本不能同時安裝的問題,見 http://www.brianpeek.com/post/2009/05/02/windows-virtual-pc-and-the-microsoft-device-emulator.aspx

2011年8月16日 星期二

使用 ExceptionCallHandler 進行例外處理

緣由

當我們開發應用程式時,難免(一定)會有bug。無論是使用者輸入不正確的資料,環境/平台因素等,只要有 bug 就是開發人員的錯。

開發人員難道只有被罵的份嗎?當然不能坐以待斃。我們開發人員必須留下錯誤的痕跡,以快速地找到錯誤的原因。

因此,我們都必須寫像下面的 Code

try
{
  //執行商業邏輯
}
catch (Exception)
{
  //記錄例外資訊到檔案或資料庫
  Console.WriteLine("對不起!發生錯誤,請洽...");
}

要如何進行例外的記錄(log)呢?

解決1:使用 EHAB

解決的方法,我都是使用 Enterprise Library 中的Exception Handling Application Block。

程式碼的部份很簡單。只需要呼叫ExceptionPolicy.HandleException 如下:

public virtual void Go2()
{
  try
  {
    throw new NotImplementedException();
  }
  catch (Exception ex)
  {
    ExceptionPolicy.HandleException(ex, "Policy");
  }
}

但config 設定的話,新手初看就很複雜了。這裡我並不想多做介紹,有興趣的話可以看這一篇

這裡有個問題,如果每一段程式都需要 try…cache 再來處理例外的話,程式碼就變的很難看。

解決2:集中一個地方處理例外

要在同一個地方處理例外其實很常見。例如在 ASP.NET 上可以在 Global.aspx.cs 中的 Application_Error 中處理

protected void Application_Error(object sender, EventArgs e)
{
    //處理 Application 所有拋出的 exception
    Exception exception = Server.GetLastError();
    ExceptionPolicy.HandleException(exception, "LogAllInFile");
}

雖然集中在一個地方處理很方便,但能做的事情也很有限,只能使用相同的 Policy 來處理例外。並且一旦到如 Global.asax 這裡來處理時,就失去了各自處理的彈性。

有沒有一個方便的解決方法,既可以各自處理,又不用每個地方寫 try..cache 這樣的 Code 呢?

解決3:使用 ExceptionCallHandler

接下來就是今天的主題了。PIAB 可以幫我們解決這樣的問題。第一步,是要讓物件可以被注入。因此物件的類別宣告不可以為sealed,Method 也必須是 virtual。

 public class Go
  {
    public virtual void Go1()
    {
      throw new NotImplementedException();
    }

第二步是在 Method 上進行 Attribute 的註記。如下:

[ExceptionCallHandler("Policy")]
public virtual void Go1()
{
  throw new NotImplementedException();
}

其中,”Policy”是Exception Policy 的名稱。

當然,不是只有這樣就可以搞定的。我們必須在實例化物件前開始進行複雜的 injection(注射)以達到我們的目的。第三步:

static void Main(string[] args)
{
  var container = new UnityContainer();
  container.AddNewExtension<EnterpriseLibraryCoreExtension>();
  container.AddNewExtension<Interception>();
  container.RegisterType<ICallHandler, ExceptionCallHandler>("ExceptionCallHandler",
      new InjectionConstructor(
          new ResolvedParameter(typeof(ExceptionPolicyImpl), "Policy")));

  container.RegisterType<Go>(
    new InterceptionBehavior<PolicyInjectionBehavior>(),
    new Interceptor<VirtualMethodInterceptor>());

  var g = container.Resolve<Go>();
  g.Go1();
}

討論

使用 ExceptionCallHandler 來解決似乎方便多了,因為可以在不同的 Method 上註記當錯誤發生時,使用不同的 exception policy 處理之。

但壞處是物件的 Method 必須都是 virtual,讓 IoC 有機會注入不同的行為。

2011年7月26日 星期二

While trying to generate your tests, the following errors occurred

當我使用 Visual Studio 2010 建立一個 Unit Test 時,發生了下面的錯誤

image

While trying to generate your tests, the following errors occurred:
Value cannot be null.
Parameter name: key

找了一下,原因很簡單。我的 TestProject 已經有相同名稱的檔名了,但在不同的目錄。VS 2010 發現有相同的 class (Full name),就會發生這樣的錯誤。

解決方法呢?就是改檔名或改 namespace 即可。

Share with Facebook