IE 9 Beta 的效能的確相當快。但畢竟是 Beta 版,難免有許多的 bug,造就一些奇特現象。
我們公司是使用 Project Sever 2003 來管理專案進度。回報專案工時是專案成員的每日工作之一。無奈,一旦安裝了 IE 9 Beta,一進到「任務」頁,網頁就被迫回到首頁,相當莫名其妙。
解法呢?正確的解法當然是等 IE 9 修正這個 bug 了。而目前我得到的暫時解法,是點選按「文件」頁,再點選「任務」頁,就ok 了。
真是怪。
IE 9 Beta 的效能的確相當快。但畢竟是 Beta 版,難免有許多的 bug,造就一些奇特現象。
我們公司是使用 Project Sever 2003 來管理專案進度。回報專案工時是專案成員的每日工作之一。無奈,一旦安裝了 IE 9 Beta,一進到「任務」頁,網頁就被迫回到首頁,相當莫名其妙。
解法呢?正確的解法當然是等 IE 9 修正這個 bug 了。而目前我得到的暫時解法,是點選按「文件」頁,再點選「任務」頁,就ok 了。
真是怪。
開發 Oracle 專案時,發生了下面的錯誤訊息
Attempt to load Oracle client libraries threw BadImageFormatException. This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed. Inner exception message: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
以下是我的開發環境
Oracle Data Access Components (ODAC) with Oracle Developer Tools for Visual Studio
Windows 7 64 bits
由於 ODAC 目前只有32 bits的程式,而VS2010方案(solution)指定Build Target 是 AnyCPU,在 IIS 7 上就會執行 64 bits。在 64 bits 的 Process 上載入 32 bits 的 Oracle client library 就會發生這樣的錯誤訊息。
解決方式也很簡單,就是在 IIS 7 上指定 Application Pool 可以跑 32 bits 的程式。
此方法只適用在開發機器上,目的是為了使用 Oracle Developer Tools For Visual Studio。在正式機上,就應該安裝 64 bits 的 Oracle Client library.
各家廠牌最喜歡比效能了。我也來試一試。
這一點真的沒話說,IE 9 完全勝出。由微軟提供的測試頁Speed Read,分別以 IE 9 beta 與 Firefox 4 beta 測試,IE 9 得到的 FPS 為30左右,而 Firefox 4 beta 則只有 5。天差地遠。
我使用 Sun spider 的 benchmark 來測試。IE 9 跑完所有 javascript 需要558.2 ms,而 Firefox 4 需求 697.4ms。嗯,IE 9 再勝出。
以http://www.howtocreate.co.uk/csstest.html 來測兩個牌子在 CSS 讀取 div 的效能。IE 9 約 16ms,而 Firefox 為10ms。在 CSS selector 的效能上 Firefox 勝出。
使用http://tools.css3.info/selectors-test/test.html 來測時,則兩者時間差不多,也都通過了測試。
ACID3 是用來評量瀏覽器是否符合標準的指標。http://acid3.acidtests.org/ 來測試,IE 9 Beta 得到 95 分,而 FireFox 4 Beta 得到 97 分。差異雖不大,但 FireFox 勝出。
雖然兩者互有勝負,但在圖形處理上,IE 9 實在勝太多了。目前來說,IE 9 整體表現較佳。
微軟的 IE 9 Beta 已經可以下載安裝了。迫不及待地,就裝了起來。
到http://www.beautyoftheweb.com ,一路跟著Download 的連結,最後根據我的Windows 版本我下載了一個2.37 MB 的IE9-Windows7-x64-enu.exe 安裝檔。哦!好小。實在出乎意外。
執行安裝程式,過程只有一個單純的視窗。
安裝完畢後,照慣例會要求重開機。
初體驗
重開機後,就發現了 IE9 更貼心的設計。超大的內容顯示區!所有的功能表,網址列,分頁等非網頁內容,全都最小化。上網本來就是看內容,誰希望這些非內容的區塊佔據我的視線呢?讚!
另外有一個小東西讓我注意到了。在內容區視窗的下方出現了這個提示。
打開之後,更貼心的設計出現了。它統計了 IE 啟動時各個 Add-On 所花的時間。我的 Add-On 最花時間的是 Search Helper,花了我 0.37 秒。要停掉嗎?先不要好了,反正全部加起來也不到 0.5 秒。 IE 9 希望所有的 Add-On 的啟動時間加起來不到 0.2秒,對我來說真是嚴苛啊。
真的如之前的傳言,IE 9 超快。Yahoo 奇摩的首頁目前算是挺複雜的了,竟也不到1秒就顯示出來。如果重新整理的話,整個畫面就像瞬間跳出來一樣。真是不同的體驗。
有個重要的搜尋輸入框不見了。天啊, IE 8 最常用的搜尋,到了 IE 9 竟然被拿掉,這怎麼可以呢?一定要告…。等一下,原來直接打在網址列就可以了。這樣一來,又少了一個佔據視窗的東西。
初體驗的經驗真是棒極了。雖然只有短短的半小時,就讓我訝異連連。看來 IE 9 真的是要大反攻了!現在就開始使用吧。
正常來說,Source Control 改使用 Visual SourceSafe (Internet)後,在打開專案的視窗中,應該可以看到 Add SourceSafe Database 的項目。
然而,我的同直卻空空如也,一片空白。為什麼呢?原來又有更新未上。見 http://support.microsoft.com/kb/943847/en-us?p=1
WPF 的強項當然要說到 Biding 了。然而 Data Binding 在 .NET 平台上到處可見。WPF 的 Binding 到底有什麼特別的呢?
下面是一個重構的過程。由最開始由未使用 Binding,一直到使用 Binding 完成後,您可以見到該 Binding 的威力。
身為一個使用者,我希望可以自行挑選表單的背景顏色
第一個版本是類似 Windows Form 的實作方式。首先打開 Visual Studio 2010, 建立一個 WPF 的應用程式。建立專案後,開啟 MainWindows.xaml,拖進一個 ListBox,並命名為 ColorListBox。如下圖
在 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 時,見到這樣的程式已經要感謝上天了。
程式運作起來,如下圖.
第一版的程式可個缺點:建構子太長,而且內含非 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; } }
為了簡少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"/>
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中。
雖說已經簡化到了不行,剩下的最後一行,難到無計可施嗎?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 了。
範例程式下載
WPF 實在是很棒的一個 Framework,而且在開發設計時,Visual Studio IDE 的輔助,讓我們的開發更具生產力。但也因為如此,當我們不朝預設的開發方式時,就容易遇到一些「地雷」。今天我就踩到一個。
問題的由來是有演變過程的。以下就一步步的演進吧。
我按標準步驟產生了一個 WPF Application後,在 MainWindow.xaml 上放了一個 Button。
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>
為了讓整個程式的按鍵看來有一致的外觀,我在 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 淺藍色。
因故,我必須移除 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 的樣式跑掉了。
這是怎麼一回事?開發的Designer 仍然是淺藍色背景--我要的樣式啊!
原因是:開發工具太強了,幫我們做了太多的事。將原來的 StartupUri 加回去,並在 Solution Explorer 下找到 obj\Debug\ 可以找到一堆由 Visual Studio 幫我們產生的程式碼。
打開 App.g.i.cs ,可以找到 InitializeComponent 這個方法。可以看到它是如何幫我們自動載入 Resource 的.
一旦我們將 StartupUri 移除掉,這段程式就會變化。整個 InitializeComponent 方法就不見了!!
這就是原因所在。
既然找到了原因,當然就知道要怎麼解了。方法有二。
第一個方法是自己補上消失的程式,並且自己將消失的 style 補上。這個方法難度較高,而且不好維護。我採用第二個方法:自訂一個 ResourceDictionary。
新增一個 ResourceDictionary 並命名為 AppResource.xaml, 並將原來在 App.xaml 的 style 移到這裡。
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 樣式就回來了。
WPF 實在設計的很棒,而 IDE 的開發輔助也讓我們快速的完成常見的需求。只是在 IDE 快速開發的背後,我們常常忽略了原來應該是我們要做的事。一旦不符合原 IDE 的快速開發條件時,就摸不著頭緒了。