2010年9月16日 星期四

IE 9 Beta 下載及安裝

微軟的 IE 9 Beta 已經可以下載安裝了。迫不及待地,就裝了起來。

下載

http://www.beautyoftheweb.com ,一路跟著Download 的連結,最後根據我的Windows 版本我下載了一個2.37 MB 的IE9-Windows7-x64-enu.exe 安裝檔。哦!好小。實在出乎意外。

安裝

執行安裝程式,過程只有一個單純的視窗。

image

安裝完畢後,照慣例會要求重開機。

image

初體驗

重開機後,就發現了 IE9 更貼心的設計。超大的內容顯示區!所有的功能表,網址列,分頁等非網頁內容,全都最小化。上網本來就是看內容,誰希望這些非內容的區塊佔據我的視線呢?讚!

image

另外有一個小東西讓我注意到了。在內容區視窗的下方出現了這個提示。

image

打開之後,更貼心的設計出現了。它統計了 IE 啟動時各個 Add-On 所花的時間。我的 Add-On 最花時間的是 Search Helper,花了我 0.37 秒。要停掉嗎?先不要好了,反正全部加起來也不到 0.5 秒。 IE 9 希望所有的 Add-On 的啟動時間加起來不到 0.2秒,對我來說真是嚴苛啊。

image

超快速度

真的如之前的傳言,IE 9 超快。Yahoo 奇摩的首頁目前算是挺複雜的了,竟也不到1秒就顯示出來。如果重新整理的話,整個畫面就像瞬間跳出來一樣。真是不同的體驗。

搜尋輸入框

有個重要的搜尋輸入框不見了。天啊, IE 8 最常用的搜尋,到了 IE 9 竟然被拿掉,這怎麼可以呢?一定要告…。等一下,原來直接打在網址列就可以了。這樣一來,又少了一個佔據視窗的東西。

image

結論

初體驗的經驗真是棒極了。雖然只有短短的半小時,就讓我訝異連連。看來 IE 9 真的是要大反攻了!現在就開始使用吧。

2010年9月7日 星期二

Visual Studio 2010 無法連線到 Visual Source over internet

正常來說,Source Control 改使用 Visual SourceSafe (Internet)後,在打開專案的視窗中,應該可以看到 Add SourceSafe Database 的項目。

然而,我的同直卻空空如也,一片空白。為什麼呢?原來又有更新未上。見 http://support.microsoft.com/kb/943847/en-us?p=1

 

SNAGHTML1b6bb2f

2010年9月5日 星期日

WPF 學習:Static Binding

WPF 的強項當然要說到 Biding 了。然而 Data Binding 在 .NET 平台上到處可見。WPF 的 Binding 到底有什麼特別的呢?

下面是一個重構的過程。由最開始由未使用 Binding,一直到使用 Binding 完成後,您可以見到該 Binding 的威力。

需求

身為一個使用者,我希望可以自行挑選表單的背景顏色

第一版:未 Binding

第一個版本是類似 Windows Form 的實作方式。首先打開 Visual Studio 2010, 建立一個 WPF 的應用程式。建立專案後,開啟 MainWindows.xaml,拖進一個 ListBox,並命名為 ColorListBox。如下圖

image

在 Code Behind 的 MainWindows.xaml.cs 上,將程式MainWindows 的建構子修改如下

public MainWindow()
{
    InitializeComponent();

    var props = typeof(Brushes).GetProperties();
    var q = from p in props
            select new
            {
                Name = p.Name,
                Brush = (Brush)p.GetValue(null, null)
            };
    ColorListBox.ItemsSource = q;
    ColorListBox.SelectedValuePath = "Brush";
    ColorListBox.DisplayMemberPath = "Name";
}

在 MainWindow 的建構子中,已經使用了 DataBinding 技術,如同 Windows Form 相同。接下來在 ColorListBox 上雙擊左鍵滑鼠兩下。並修改 EventHandler 如下

private void ColorListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.Background = ColorListBox.SelectedValue as Brush;
}

到這裡,程式已經可以運作,而且程式碼相當乾淨。 Code Review 時,見到這樣的程式已經要感謝上天了。

程式運作起來,如下圖.

image

第二版:重構,建立一個 NamedBrush

第一版的程式可個缺點:建構子太長,而且內含非 UI 的邏輯,即使用 Reflection 讀取所有 Brushes 的 public property。
這一個重構的目的,就是將這一段程式拆出來。改放到一個 NamedBrush 類別。

using System.Linq;
using System.Windows.Media;

namespace WpfApplication2
{
    public class NamedBrush
    {
        public Brush Brush { get; set; }
        public string Name { get; set; }
        public static NamedBrush[] All { get; set; }

        static NamedBrush()
        {
            var props = typeof(Brushes).GetProperties();
            var q = from p in props
                    select new NamedBrush
                    {
                        Name = p.Name,
                        Brush = (Brush)p.GetValue(null, null)
                    };
            All = q.ToArray();
        }
    }
}

而 MainWindow.xaml.cs 就可以簡化如下

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        ColorListBox.ItemsSource = NamedBrush.All;
        ColorListBox.SelectedValuePath = "Brush";
        ColorListBox.DisplayMemberPath = "Name";
    }

    private void ColorListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        this.Background = ColorListBox.SelectedValue as Brush;
    }
}

第三版:在xaml中設定屬性

為了簡少Code behind 的程式,我們將建構子中的 ColorListBox 的屬性值設定陳述句移到 xaml 中。 也就是將下面這兩行

ColorListBox.SelectedValuePath = "Brush";
ColorListBox.DisplayMemberPath = "Name";

移到 xaml 中,如下

<ListBox Height="213" HorizontalAlignment="Left" Margin="76,12,0,0" Name="ColorListBox" VerticalAlignment="Top" Width="353"
  SelectedValuePath="Brush" DisplayMemberPath="Name"/>

 

第四版:Binding

WPF 特有的 Binding 可以取代一些 Event Handler,如同在WPF 學習:Binding中已經使用過這樣的技巧。因此, ColorListBox_SelectionChanged 這樣簡單的有一些可以移到 xaml 中。

<Window x:Class="WpfApplication2.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" Background="{Binding ElementName=ColorListBox, Path=SelectedValue}">

意思是:Window 的 Background 值繫結來至 ColorListBox 的 SelectedValue。

到了這個步驟,整個 Code behind 只剩下

using System.Windows;

namespace WpfApplication2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            ColorListBox.ItemsSource = NamedBrush.All;
        }
    }
}

換句話說,只剩一行的 ColorListBox.ItemsItemsSource = NamedBrush.All; 這一行程式要寫。其他的都移到了 xaml中。

第五版:使用靜態 Binding

雖說已經簡化到了不行,剩下的最後一行,難到無計可施嗎?WPF 還有一招:StaticBinding。在 xaml 宣告一個 Window Resource 如下

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525" Background="{Binding ElementName=ColorListBox, Path=SelectedValue}">
    <Window.Resources>
        <l:NamedBrush x:Key="NB" />
    </Window.Resources>

注意到我增加了 xmaln:l=’clr-namespace:WpfApplication2’ 這一行 namespace 宣告。

最後,在 ColorListBox 的 ItemsSource 屬性設定如下

<ListBox Height="213" HorizontalAlignment="Left" Margin="76,12,0,0" Name="ColorListBox" VerticalAlignment="Top" Width="353"
                 SelectedValuePath="Brush" DisplayMemberPath="Name" 
                 ItemsSource="{Binding Source={StaticResource ResourceKey=NB}, Path=All}"/>

這樣一來,Code Behind 的程式就與最初的相同了。

using System.Windows;

namespace WpfApplication2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

討論

為什麼我們汲汲營營的要把 xaml.cs 的程式降到0行客製程式呢?第五版的步驟,為了將一行的建構子程式,我們修改了 xaml 三個地方,這樣划的來嗎?

其實,這樣做有兩大好處。第一項好處,是沒有 Code behind 的程式後,美工的部份可以完全交給設計人員。設計人員只需使用 Expression Blend 來設計樣式,完全不必懂程式如何寫作,就可以使用 Binding 的方式設計行為。

第二項好處,是UI 的資料(Model)完全分離,這有利於單元測試。對於容易進行測試的 NameBrush 類別進行單元測試,而難以進行測試,又常常改化的 UI就可以進行 Coded UI Test 了。

範例程式下載

2010年9月3日 星期五

WPF 應用程式,App.xaml 不使用 StartupUri 時無法套用 ResourceDictionary

前言

WPF 實在是很棒的一個 Framework,而且在開發設計時,Visual Studio IDE 的輔助,讓我們的開發更具生產力。但也因為如此,當我們不朝預設的開發方式時,就容易遇到一些「地雷」。今天我就踩到一個。

問題

問題的由來是有演變過程的。以下就一步步的演進吧。

步驟1: 標準的 Style

我按標準步驟產生了一個 WPF Application後,在 MainWindow.xaml  上放了一個 Button。

image

Xaml 如下, 非常簡單

<Window x:Class="WpfApplication2.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">
        <Grid>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="40,36,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
    </Grid>
</Window>

 

 

步驟2: 套用標準的 Style 到每一個 Button

為了讓整個程式的按鍵看來有一致的外觀,我在 App.xaml 上增加了 Button Style。App.xaml 如下,也非常的 easy

<Application x:Class="WpfApplication2.App"
                         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         StartupUri="MainWindow.xaml">
        <Application.Resources>
        <ResourceDictionary>
            <Style TargetType="Button">
                <Setter Property="Background" Value="LightBlue" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

而無論在開發階段或執行階段,Button 的樣式果然成我預期的背景顏色LightBlue 淺藍色。

image image

步驟3:移除 StartupUri

因故,我必須移除 App.xaml 中的 StartupUri,並自行建立 MainWindow 的 instance。修改後的 App.xaml如下

<Application x:Class="WpfApplication2.App"
                         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         > <!--注意到我移除了 StartupUri-->
        <Application.Resources>
        <ResourceDictionary>
            <Style TargetType="Button">
                <Setter Property="Background" Value="LightBlue" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

而 App.xaml.cs 如下

using System.Windows;

namespace WpfApplication2
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var mainWindow = new MainWindow();
            mainWindow.Show();
        }
    }
}

程式可以執行,但問題來了:執行時期,Button 的樣式跑掉了。

image

這是怎麼一回事?開發的Designer 仍然是淺藍色背景--我要的樣式啊!

原因

原因是:開發工具太強了,幫我們做了太多的事。將原來的 StartupUri 加回去,並在 Solution Explorer 下找到 obj\Debug\ 可以找到一堆由 Visual Studio 幫我們產生的程式碼。

image

打開 App.g.i.cs ,可以找到 InitializeComponent 這個方法。可以看到它是如何幫我們自動載入 Resource 的.

image

一旦我們將 StartupUri 移除掉,這段程式就會變化。整個 InitializeComponent 方法就不見了!!

這就是原因所在。

解決

既然找到了原因,當然就知道要怎麼解了。方法有二。

第一個方法是自己補上消失的程式,並且自己將消失的 style 補上。這個方法難度較高,而且不好維護。我採用第二個方法:自訂一個 ResourceDictionary。

新增一個 ResourceDictionary 並命名為 AppResource.xaml, 並將原來在 App.xaml 的 style 移到這裡。

SNAGHTML8e2c6c

AppResource.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="Button">
        <Setter Property="Background" Value="LightBlue" />
    </Style>
</ResourceDictionary>

改用 。修改App.xaml 如下

<Application x:Class="WpfApplication2.App"
                         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         > <!--注意到我移除了 StartupUri-->
        <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="AppResource.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

然後,執行時期的 Button 樣式就回來了。

image

結論

WPF 實在設計的很棒,而 IDE 的開發輔助也讓我們快速的完成常見的需求。只是在 IDE 快速開發的背後,我們常常忽略了原來應該是我們要做的事。一旦不符合原 IDE 的快速開發條件時,就摸不著頭緒了。

2010年8月27日 星期五

在 Exchange 2007 上的進行會議室管理

會議室、投影機等資源,在企業通常需要預約。如果有人已經預約了,就應該自動拒絕。這樣的需求普遍地發生在每個公司中。

以往在 Exchange 2003 的會議室管理,必須使用會議室的帳號登入某台有安裝 Outlook 的電腦,在會議的選項中設定。這個方式在 Exchange 2007 是行不通的。

那要如何在 Exchange 2007 上進行會議室管理呢?

其實,Exchange 2007 的設定就更簡單了。是使用該資源的帳號在 OWA 中登入並設定即可。步驟如下:

1  登入 OWA

2  在網頁右上角點擊「選項」連結

image

3  在左方的 Menu 中點擊「資源設定」

image

4  設定「資源排定選項」

重點在於勾選「自動處理會議邀請與會議取消通知」,並設定其下的選項。

image

其他的選項就自己看看吧!

5 記得儲存哦!

image

參考

管理資源排程

遇到 Nulls 時的排序方式

今天看到了一個 Nulls Last 的 Oracle 語法,順便回頭研究 SQL Server 上要如何實作。

問題

當查詢遇到了排序的欄位中有 Null 值時,要如何將 Null 值改排在前還是排在後。

SQL Server 版

SQL Server 總認為 null 值是比較小的值。當order by 的欄位中有 null 時,null 的資料會先列出。相反地, order by …. desc 時會最後列出。

如果要改變,只好搞一下小技巧

--排列時,field1為null 的最後才列出
select * from tableName
order by case when field1 is null then 1 else 0 end, field1 asc

Oracle 版

Oracle 則認為 null 值是比較大的值。

對於 null 值要如何排序,Oracle 的獨特的語法來解決。

select * from tableName order by field1 NULLS First;   --Null 值先列出。此為預設

select * from tableName order by field1 NULLS Last;  -- Null 值後列出。

結論

這個問題,SQL Server 還是可以做到,只是要想一下小技巧。 看來這個地方 Oracle 比較貼心呢! 。

2010年8月26日 星期四

Oracle 的字串比對

問題

我想要查詢資料庫的Schema資訊時,以下列語法查詢,卻查不到資料。為什麼?

select * from sys.ALL_TAB_COLUMNS
where owner = 'hr'

原因

原來,Oracle 是有分大小寫的。此與 SQL Server 的預設值不同。為了查詢,必須改成大寫才能找到資料。

select * from sys.ALL_TAB_COLUMNS
where owner = 'HR'
image

不分大小寫

查詢時,如何不區分大小寫呢?例如在一個新聞上稿的資料庫中,查詢一篇文章內有 SQL Server 這個字串時,就必須不區分大小寫。

原來 Oracle 有兩個設定,NLS_COMP 與 NLS_SORT

NLS_COMP

這個設定是用來字串比對用的,適用於 where 子句中。

可設定的值

  • BINARY : 所有比對是根據其字元的 binary 值來比對。所以一定會分大小寫。
  • ANSI:遵守 NLS_SORT 的設定。這是10g R2 以前的設定方式。10g R2 以後仍在,只是為了向前相容性。
  • LINGUISTIC:遵守 NLS_SORT 的設定。這是 10g R2 後的設定方式。

設定方式

任選一方式來設定:

  • 環境變數:SET(export) NLS_COMP=<binary|linguistic>
  • 在連線的 session中 內設定:ALTER SESSION SET NLS_COMP=<binary|linguistic>;

NLS_SORT

NLS_SORT 設定 order by 子句的排序方式。

可設定的值

  • BINARY : 所有比對是根據其字元的 binary 值來排序。
  • V$NLS_VALID_VALUES : All sorting is done in accordance to a named linguistic definition. This means that Oracle will sort in accordance to a particular locale (GERMAN, POLISH, FRENCH, etc.).These valid named definitions may be obtained by querying the V$NLS_VALID_VALUES where parameter = `SORT'. Just be aware that all the values in this view also have a hybrid definition by adding a suffix of _CI (case insensitivity

設定方式

  • 環境變數:SET(export) NLS_SORT=<valid_value>
  • 在連線的 session中 內設定:ALTER SESSION SET NLS_SORT=<valid_value>;

範例

不區分大小寫

alter session set NLS_COMP=LINGUISTIC; --遵照 NLS_SORT 的設定,即下面的不區分大小寫
alter session set NLS_SORT=BINARY_CI; -- 不區分大小寫
select * from sys.ALL_TAB_COLUMNS where owner = 'Hr'
執行結果如下

 

image

 

參考

Share with Facebook