2011年12月31日

WPF – MVVM (三)

做到這邊,我們已經做了很大部分的分離了,但是實際上,我們還有一個地方還沒處理,那就是放在View那邊的邏輯,也就是按下Button時的事件,所以我們這邊再進一步的去處理。

移除View裡面的邏輯

首先我們先把View裡面的邏輯移除,並把它放到ViewModel裡面去,所以我們先將View裡面的東西移除掉,現在裡面真的是空空沒有東西了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

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

接下來我們來看看移到ViewModel產生了甚麼變化。

邏輯移到ViewModel

到這邊,我相信大家就會產生一個疑問,那View裡面的按鈕按下後,要怎樣去呼叫ViewModel裡面的東西呢??其實我們還是會使用一個Binding的方式,只是這次Binding的是一個ICommand的型別;接下來我們繼續處理ViewModel,這次在ViewModel加了一個ICommand型別的參數UpdateTitleNmae,他會回傳一個實作ICommand的RelayCommand實體,並且傳入兩個方法UpdateTitleExecute,CanUpdateTitleExecute ( 沒錯,不要懷疑,傳入進去的是方法)。等下我們會建立RelayCommand類別,到時候就會看到,另外UpdateTitleExecute這個方法裡面定義著要處理的邏輯,也就是從View搬過來的邏輯;而CanUpdateTitleExecute代表著是否可以執行此方法,因為我們這邊一定都會讓此方法( UpdateTitleExecute )可以動作,所以CanUpdateTitleExecute就直接回傳True。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Input;

namespace WPFMVVM3
{
    //實作InotifyPropertyChanged
    public class PostsViewModel : INotifyPropertyChanged
    {
        public Posts posts{ get; set;}
      
        public event PropertyChangedEventHandler PropertyChanged;

        //定義一個ICommand型別的參數,他會回傳實作ICommand介面的RelayCommand類別。
        public ICommand UpdateTitleName { get { return new RelayCommand(UpdateTitleExecute, CanUpdateTitleExecute); } }

        public PostsViewModel()
        {
            posts = new Posts { postsText = "", postsTitle = "Unknown" };
        }

        public string PostsTitle
        {
            get { return posts.postsTitle; }
            set 
            {
                if (posts.postsTitle != value)
                {
                    posts.postsTitle = value;
                    RaisePropertyChanged("postsTitle");
                }
            }
        } 

        //產生事件的方法
        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        //更新Title,原本放在View那邊的邏輯,藉由繫結的方式來處理按下Button的事件。
        void UpdateTitleExecute()
        {
            PostsTitle = "SkyMVVM";
        }

        //定義是否可以更新Title
        bool CanUpdateTitleExecute()
        {
            return true;
        }
    }
}

這樣,ViewModel就完成了,接下來是處理RelayCommand。

撰寫RelayCommand

RelayCommand是實作ICommand的類別,一開始我們就可以看到定義了Func和Action,這兩個就是用來參考到剛剛傳入進來的兩個方法,並進行了一些的處理。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Diagnostics;

namespace WPFMVVM3
{
    public class RelayCommand :ICommand
    {
        
        readonly Func _canExecute;
        readonly Action _execute;

        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action execute, Func canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {

                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {

                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        [DebuggerStepThrough]
        public Boolean CanExecute(Object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        public void Execute(Object parameter)
        {
            _execute();
        }
    }
}

最後,我們必須重新調整XMAL。

調整XMAL

最後的一個動作,我們將Button的Click屬性拿掉了,改成Command屬性,並將之Binding到ViewModel的UpdateTitleName屬性,就完成了。

<Window x:Class="WPFMVVM3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFMVVM3"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <!-- 實例化PostViewModel -->
        <local:PostsViewModel />
    </Window.DataContext>
    <Grid>
        <Label  Content="{Binding PostsTitle}"    Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="145,13,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding UpdateTitleName}" />
    </Grid>
</Window>

以上就完成了!

結尾

到這邊就算是手工打造MVVM的一個段落了,其實現在有許多的Framework可以幫我們處理一些繁雜的事物,但如果能了解原理,我相信會更有幫助,所以這次用了循序漸進的方式,來記錄這些內容,也希望能給大家一點幫助!

參考資料

2011年12月29日

WPF – MVVM (二)

上一篇講到利用Binding來讓View與ViewModel的繫結,還有ViewModel與Model的關係,但離整個MVVM還有一點點的距離,接下來,我們繼續看下去。 ( 感覺好像漫畫連載喔…放心我不會和某獵x一樣拖稿的。 )

Button事件處理

上一篇我們還沒實際處理按下Button的功能,這裡我們實際的處理一下吧。

下面是View的cs檔,我們會建立一個私有的屬性,這個屬性會利用base.context將XMAL那邊實例化的PostsViewModel傳回來,另外,傳回來的物件需要轉型一下;接下來,我們就可以撰寫Button的Click事件,在這邊,我們將新的值"SkyMVVM"這個Title名稱,傳給PostViewModel ( 實際上會寫回到Model裡面 ),當然這樣子Label是不會改變的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFMVVM
{
    public partial class MainWindow : Window
    {
        PostsViewModel _postsViewModel;

        public MainWindow()
        {
            InitializeComponent();
            _postsViewModel = (PostsViewModel)base.DataContext;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            //這裡還沒辦法通知View,告訴View要更改Label的content
            _postsViewModel.PostsTitle = "SkyMVVM";
        }
    }
}

這邊,如果要Label改變,最直接的做法是在Button Click裡面再加上Label.Content = “SkyMVVM”這行,這樣就可以讓Label馬上的改變,但這樣做當然不好啊,第一,這樣就失去了Binding的意義了,第二,這樣做,Button Click就和Label有了很深的關係。

所以最好的做法是,當我們的PostViewModel的PostsTitle改變的時候,自動讓Label的Content去做改變,但要怎樣做呢?

INotifyPropertyChanged

登登豋登!沒錯我們就是要利用INotifyPropertyChanged這個介面,這個介面裡面含有一個PropertyChanged事件,此事件可以更新繫結的目標喔!

所以我們改寫一下ViewModel的程式碼,讓他實作InotifyPropertyChanged,並且寫一個Function ( RaisePropertyChanged ),此function會產生一個事件,並通知繫結的Label更改Content。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WPFMVVM2
{
    //實作InotifyPropertyChanged
    public class PostsViewModel : INotifyPropertyChanged
    {
        public Posts posts{ get; set;}
      
        public event PropertyChangedEventHandler PropertyChanged;

        public PostsViewModel()
        {
            posts = new Posts { postsText = "", postsTitle = "Unknown" };
        }

        public string PostsTitle
        {
            get { return posts.postsTitle; }
            set 
            {
                if (posts.postsTitle != value)
                {
                    posts.postsTitle = value;
                    RaisePropertyChanged("postsTitle");
                }
            }
        } 

        //產生事件的方法
        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

做到此,我們就成功地讓ViewModel的屬性和Label進行分離了,也就是說ViewModel可以完全不用知道View了!但這樣就算完成MVVM了嗎??還沒還沒,我們繼續看下一篇吧。

參考資料

WPF – MVVM (一)

小弟本來是專注於網頁設計,最近被公司抓去寫WPF,所以就開始了新的生涯XDD,而既然講到WPF,就不可能不需要知道MVVM,翻了一些國外文章,寫的還不錯,小弟我就邊看邊把他記錄一下,並分享給大家吧,不過因為MVVM的東西比較多,所以小弟我也會分成好幾篇慢慢地來講解。

What’s MVVM

MVVM當然也是縮寫,也就是Model-View-ViewModel,簡稱MVVM,他也算是一種設計樣式,目的是為了讓各自的相依性降低,這樣以後也比較好維護與測試,而MVVM的意思如下。

  • Model是一個來自服務或資料庫數據的類別。
  • View就是一個顯示的介面,預計是要將資料展現出來。
  • ViewModel就如同膠水般,它把Model和View黏合起來。它將Model包裝起來,而且 ViewModel還會控制View的應用部分,例如在View那邊按下按鈕後,要處理的動作,實際上會放在ViewModel。

而它們之間的關係如下圖般,View也就是XAML,透過Data Binding技術與View Model繫結,但實際上ViewModel是不會知道哪個View繫結了它( ViewModel );而ViewModel與Model的關係也是如此,Model永遠不知道他被哪個ViewModel所參考到,而ViewModel則會參考到Model;換言之,就是View會知道ViewModel,ViewModel會知道Model,這種單向的關係。

image

View與ViewModel

其實如上圖所說,其實View與ViewModel溝通是利用了Binding的技術;我們可以利用下圖更明確的理解,

image

逐步進行(一)

不過我想講了那麼多,還不如實際的一步一步來走走看,我想感覺是比較明顯的,首先,我們先實作一個簡單的MVVM架構試試看,而這個畫面是這次預計的目標,其實滿簡單的,就是會顯示一個文章Title ( 我稱取為PostsTitle ),然後按下按鈕後,會改變Title,雖然這畫面看起來沒啥成就感,但至少我們可以從很簡單的例子看到MVVM。

image

Model

提到MVVM,當然第一步我們要先把Model建立起來,假設這套系統是要處理文章資料的管理 ( 實際上我並不會把它完成,這裡只是假設要建立文章管理系統 ),既然如此,最重要的Model,顧名思義就是文章了,假設我們此類別取名為Posts,並開始撰寫此類別。

以下是Posts Class的程式碼,超級簡單,就兩行,裡面兩個屬性。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WPFMVVM
{
    public class Posts
    {
        public string postsText { get; set; }
        public string postsTitle { get; set; }

    }
}

到這邊我們的Model就建置好了,接下來我們要做的是黏合View和Model的ViewModel!

ViewModel

其實也不長,但比較特別的是,ViewModel裡面的屬性會參考到Model,換言之,Model不會知道有那些ViewModel用到他 ( 因為Model裡面並沒有參考到ViewModel. ),然後我們會定義一些方法,讓Model的屬性可以被存取到 ( 例如這邊的PostsTitle方法 )。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WPFMVVM
{
    public class PostsViewModel
    {
        public Posts posts{ get; set;}
      
        public PostsViewModel()
        {
            posts = new Posts { postsText = "", postsTitle = "Unknown" };
        }

        public string PostsTitle
        {
            get { return posts.postsTitle; }
            set { posts.postsTitle  = value; }
        } 
    }
}

接下來,我們再來處理View的部分。

View

這個地方比較要注意的是Window標籤裡面,我們必須要定義一個local這個NameSpace,當然這個local你也可以取名其他的名稱,而後面接的就是我們剛剛定義ViewModel的NameSpace,其次就是DataContext標籤裡面,我們直接實例化PostsViewModel出來;最後利用Binding將Label的Content細節至PostsViewModel的PostsTitle。

<Window x:Class="WPFMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFMVVM"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <!-- 實例化PostViewModel -->
        <local:PostsViewModel />
    </Window.DataContext>
    <Grid>
        <Label  Content="{Binding PostsTitle}"    Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="145,13,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
</Window>

這樣就是MVVM!那麼簡單!?,當然不是,這只是簡單的一個Binding而已,但不管怎樣,我們已經看到了Model和ViewModel是如何處理的,也可以清楚的了解了Model、ViewModel與View之間的關係,雖然目前只有利用Binding來將PostsTitle顯示於Label,按下Button也沒啥反應 ( 因為我還沒實作阿XDD ),我們下一篇繼續看下去。

參考資料

2011年12月28日

TFS – BurnDown燃燒圖

在我們建立好Task,且進入每個人自己的開發流程後,我們通常都會於每天下班結束前,重新KeyIn剩餘時間,這件事是一定必須要做的事情,這樣才能真正的反應到目前的工作進度,而不是到最後的階段,才一次爆出來! ( 我好像常常這樣QQ )

下班前,我們可以先進入borard這裡,並點兩下紅色框框的這個區塊。

image

底下的AssignedTo( 指派給誰 ) 其實是有帳號的,我把它馬賽克了,另外我們先看State ( 狀態 )這邊,目前的狀態是In Progress ( 執行中 ),剛好是對應到上圖的位置,所以當上圖拉動的時候,其實這個也回連動喔!接下來,是Remaining Work ( 剩餘工作 ),其實我們要修改的就是這裡,例如今天下班前,確認此工作還需要兩個小時,所以我們可以把這邊改成2。

image

當回到主頁面的時候,我們就可以感受到主頁面的改變了,而右邊的Burndown就是等下要講的一個重要圖表,也就是燃燒圖!! ( 有沒有感覺很High! )

image

當我們點一下BurnDown圖表,會出現下面這個放大版的圖,我們可以看到X軸是時間,這個時間也就是這次Sprint所定義出來的時間,而Y軸的部分,則代表著還沒工作的剩餘時間,也就是每個Task剩餘工作的總和,黑線( Ideal Trend )是理想曲線,也就是說,理想的狀況下,每天的工作會越來越少,到1/2號時,就會完成了,紅線( Actual Trend )是實際曲線,也就是目前工作實際的線條。

image

我們繼續以上面的這個圖來解釋,在12/26號的時候,我們剩餘的工作量為4小時,而1/2號的時候,是預計結束,所以應該是要剩餘0小時,第二天的時候,因為我打混,四處聊天沒工作,所以還是維持4小時,所以在12/27號的時候,就超出了理想曲線( 黑線 ),這也代表這需要注意一下了,而12/28號,因為被老闆發現,被罵了一頓,所以認真工作一整天,所以剩餘工作剩下2個小時,所以整個舊低於理想曲線,所以我們可以從這個圖表,輕鬆地看到目前整個進度與狀況,是否能於預定時間內完成。

當然,真實的專案裡面,這個表一定會起起伏伏,但大家還是必須每天都要更新,重點不在於監督每個人,而是能藉由此圖表,了解目前整個專案的狀態,當有任何問題需要處理,也能及早發現,及早治療。

2011年12月27日

Study4 點課幫 Web Design Club 12-0107 朝向未來!HTML5 活動展開!

2/3更新 - 活動順利結束!

這次很抱歉,拖了超久才po這個回顧文章,實在是因為這陣子太忙了,然後又碰上過年,整個就是來不及處理這些東西,不過未來的點課幫委員會也成立了,相信大家的攜手幫忙下,會讓這個公益活動越來越順利!!

這次很感謝大家熱情的支援與不斷地幫忙打廣告宣傳,結果來的程式設計師還是比網頁設計師多啊XD,也因為是第一次辦給網頁設計師的,所以有些東西也還在調整拿捏,希望未來能更好,而這次也得到許多外界的鼓勵與支持,也讓我們在中部,跨出了小小的一步,謝謝各位!

此外,這次活動太High了,熊熊就給他忘記拍照了= =,未來會請人成立攝影組,幫忙拍一些好照片XDD,另外,點課幫的FB也成立了喔!也歡迎大家按個讚!

第一場 HTML5 投影片下載

原本這個應該是很好講的主題,但範圍有點沒拿捏好,講得太廣了,變成甚麼東西都提一點,然後台下就變得很無聊…( 好啦,我承認我最近有點票房毒藥QQ ),未來針對主題,可能還是要細膩一點,抓準確一點,總之,這次缺點還滿多的。

第二場 SEO

這是個很好玩的主題,大家聽得很有興趣,也學到許多小撇步來讓搜尋引擎更容易找到,大家的反應也超熱烈,未來這種課程,也會多多規劃。

-- 我是舊資訊分隔線 --

第五次活動展開!

期待已久,針對網頁設計師的Study4點課幫活動,終於敲定於1月7號(六)展開!這次為了配合即將到來的農曆年,所以特別提早舉辦,也讓各位能在後面的日子裡乖乖地在家大掃除!(疑!?)

這次是第五次的Study4點課幫活動,也是新年後的第一場,為了迎接新的未來,我們也特別將主題訂定為朝向未來!HTML5!希望藉此來迎向網際網路新的世紀。

這次主題主要區分為三個,第一場次在介紹HTML5的走向與新功能講解,第二場次會介紹HTML5與目前瀏覽器的相容性與解決方案;而最後,用HTML5寫出超漂亮的網頁,要如何讓大家看到,才是重點中的重點,所以最後一個場次,則會教大家如何做好網頁的SEO,讓搜尋引擎把你的網頁排到前面,讓大家看的見!

Study4 點課幫 Web Design Club 12-0107 朝向未來!HTML5 - 邊吃邊喝邊學習!

( 如果有需要餐點服務者,我們會幫忙準備費用150元以內之食物,並於報名時告至 ,如果不需要餐點,報完名後,免費入場喔! )

時間 : 2012 01/07 (六) 12:30 進場,13:00 ~ 17:00
地點 : 台中市西區民權路239號17樓
課程大綱:

  1. 朝向未來!HTML5! – Sky
  2. 接納過去!HTML5! – Sky
  3. 網頁設計師進階學習,如何進行搜尋引擎最佳化 – Cary

檢視較大的地圖

2011年12月25日

Visual Studio - 智慧型IntelliTrace功能

之前答應了朋友,寫一篇關於Visual Studio IntelliTrace的文章,但熊熊就給他忘記了XD,後來前陣子去上了神人,且超可愛的王寧疆老師(this)的課 ( 覺得老師超憨厚超可愛的啦! ),剛好又提到了IntelliTrace,於是又喚醒了小弟愚笨的記憶XDD,所以趕快補上這篇..

強大的Visual Studio

相信每個人寫.NET都會用到Visual Studio,但是有多少人真的發揮出Visual Studio這個IDE的完整功能呢?,小弟我大概連一半都發揮不出來吧…,尤其又有許多功能不是預設的,如果沒有高人指點,小弟我大概一輩子都會把Visual Studio當作超高級文字編輯器吧,所以為了回饋高人的指點,也借花獻佛一下,把此資訊po到網路上,希望能給更多人感受到這超級強大的Visual Studio。

開啟智慧型IntelliTrace

首先,小弟就先不介紹甚麼是IntelliTrace了,俗話說的好,沒圖沒真相,沒實際體驗,是不知道這強大的功能的,所以小弟我就先教大家如何開啟這強大的功能吧。

首先於Visual Studio裡面的選單工具,然後選項。

image

然後點選IntelliTrace,並於右邊選擇IntelliTrace事件和呼叫資訊。當然,這樣效能也吃的比較多就是了。

image

這樣就算開啟完成了,接下來,我們實際運作看看。

使用智慧型IntelliTrace

使用方法和平常設定中斷點的方式其實沒有甚麼兩樣,如下圖,這是我的一個ASP.NET MVC的DEMO,我設定了一個中斷點。

image

這時候,執行偵錯,然後跑到這行的時候,ㄟ,有沒有發現不一樣?沒錯,偵錯的地方出現箭頭了。

image

平常沒有開啟智慧型IntelliTrace時,偵錯點到哪邊,就只會停在哪邊,然後我們可以用下一步下一步的方式一步一步慢慢走,但是是沒辦法回頭的,但是當開啟智慧型IntelliTrace時,就可以任意地往回走,這對於偵錯,可是一大幫助阿!!

關於智慧型IntelliTrace

  1. 此模式只適用於Visual Studio Ultimate版本。
  2. 此模式會記錄所有發生的事情。
  3. 此模式能產生一特定的檔案。
  4. 也因此,能與Test Manager、Unit Test、Build做整合。

雖然感覺上只是小小的功能,但其實此功能和Test Manager、Unit Test做了很大的整合,以前,我們寫程式的時候,如果發佈到測試者端,被測試者搞掛了,通常會做幾種處理方式,一個是聽測試者講,怎樣錯,怎樣錯,但實際上,都和測試者表達的不一樣XDD,其次就是遠端連線過去看,看看測試者如何搞掛,但這樣有時候,又會聽到測試者碎碎念QQ,然後再回來自己做一次,實在是很費工,所以使用智慧型IntelliTrace就可以輕易的將測試人員偵測出錯誤時,將完整的資訊回報給Developer!,但缺點是只支援最高版的Visual Studio,所以,以後別忘了,如果老闆要買Visual Studio,請指名最高版本喔!

最後,當然這只是智慧型IntelliTrace的一小部分,未來小弟再慢慢補完吧!

TFS – 建立Task

這裡都是依據Scrum為基礎,如果不清楚Scrum可以先參考這裡

Task

當我們收到一堆的Product Backlog,並且由老闆決定哪一個Product Backlog最優先處理,排入Sprint後,我們就要進入下一個階段,訂定Task。

通常一個Product Backlog只是由使用者提出的一個需求,但實際上,這個需求可能需要處理很多的事情,例如我們前一篇新增的"學習Product Backlog",實際上,除了學習、實作、還需要寫Blog才算完成,而要處理的每一件事情,其實都是一個Task,一個Task的時間,不宜超過2天,如果太長,就建議應該拆得更細。

這邊,我們開始看看,Team Foundation Service要如何建立Task;下圖是主畫面,我們可以直接按+ Task這個按鈕來新增,不過通常我都不會這樣處理,而是會先去看,目前有哪些Task;所以依舊選擇View Backlog。

image

進入後,我們要處理的是第一次Sprint的Product Backlog,所以點選Sprint 1,就會進入以下畫面,我們可以看到目前的Sprint 1已經有一個Product Backlog,也就是"學習Product Backlog",我們按一下加號的按鈕,就可以輕鬆的新增"附加在Product Backlog"底下的Task。( 這邊說明一下,在TFS裡面,預設每個Item Work都是互相獨立的,但可以將Item Work進行關聯;如果我們於首頁直接新增Task,那還要指定關聯哪一個Product Backlog,但如果用以下的方式,就會比較輕鬆明瞭的達成 )

image

按下加號的按鈕,就會出現和新增Product Backlog很像的視窗,首先我們在標題新增研究Product Backlog。

AssignedTo同樣是指派給誰。

Remaining Work是代表剩餘工作時間,未來每天都必須去修改此時間。

Backlog Priority表示此優先順序。

此外,右下角有一個LINKS,點選後會出現關聯的Product Backlog,如前面所說,如果是直接新增Task的話,就必須要在這邊選取關聯的Product Backlog。

最後我們打上關於此Task的描述,完成後如下圖,當然還有些東西目前沒講到,未來用到後,會在解釋。

image

完成後就會回到View Backlog的頁面,我們就可以看到多增加了Task進來了!( 我增加了兩個Task,一個是研究,一個是發表 ),其次,我們也可以從右邊明細看到一些相關的資訊。

image

再回到主畫面後,也可以發現主畫面的資訊也有點變動了,因為我新增了兩了Task,共計6小時,這部分也在主畫面順利地呈現。

image

最後,我們在主畫面點選一下View board。

image

我們就可以看到此圖表,此圖表就像是在白板上面貼一堆便條紙,我們可以看到整個團隊目前的工作項目與進度 ( 這裡團隊有兩個人,只是被我塗掉了 ),TODO代表著待執行,IN PROGRESS表示執行中,DONE當然就是完成了,這裡假設研讀Product Backlog已經在執行了,我們就可以直接將這個很像便利貼的東西,直接拉到IN PROGRESS裡面。

image[34]

拉完後,就像這樣,這樣就代表"研究Product Backlog"這個Product Backlog正在執行中。

image[38]

到這邊Task就算是新增完成啦!

下一篇,工作完成後!?

TFS – 建立Product Backlog

Product Backlog是Scrum裡面的一個專有名詞,如果不清楚Scrum可以先參考這裡

Product Backlog Item

在Team Foundation Service裡面,要建立Product Backlog,其實就是在建立Team Foundation Service Work Item裡面的Product Backlog Item。

當我們第一次進入Team Foundation Service時,可能會看到這個畫面,我們可以從左邊選擇要進入哪一個Team Project。

image

當我們選擇了其中一個Team Project,就會進入如圖,接下來我們就可以利用Product Backlog Item按鈕,來新增許多的Product Backlog。( 如果沒有設定Sprint日期的人,可以參考這篇設定第一次的Sprint日期 ,這裡我假設第一次衝刺的時間為12/26號~1/2號,通常衝刺間隔以兩周到一個月最為恰當。)

image

接下來會跳出此視窗,讓你Keyin一些資訊,我們首先假設這次老闆的其中一個需求是要我們學習Product Backlog,並把學習到的資訊,傳授給別人;那我們在第一個方框上打上這個Product Backlog的名稱。

AssignedTo就代表著此Product Backlog要給哪個PM去做處理。

Iteration表示要在哪個時程完成,假設老闆現在提出來一堆需求,我們還沒確定,所以暫時先保持不動。

Effort代表著此故事情節所需要花費的點數,你可以假設每小時一個人代表一點,也可以表示一個團隊做一小時代表一點,總之,這是初步估計的點數。

BusinessValue表示著商業的價值,依據老闆覺得這些事情的重要性,來給數值高低。

Area可以替這個Item進行分類,我們把這個學習Product Backlog這個類別歸到Study區域裡面。

最後,我們描述一下這個Product Backlog真正要做的內容是甚麼。

完成後就如下圖。

image

按下Save and Close後,會回到主畫面,假設老闆給了一堆需求後,也確認那些要先執行,我們就可以將這些Product Backlog排入第一次的Sprint ( 這裡當然不可能把所有Product Backlog排入每次的Sprint裡,因為每次的Sprint裡面,時間與人力都是有限的 )。

我們可以選擇右邊的View Backlog進行檢視與編輯。

image

左上角的Product Backlog會把所有的Product Backlog列出來,其次,點選Sprint 1或是Sprint 2,就只會列出被歸類至Sprint 1或是Sprint 2的Product Backlog。( Sprint 1與Sprint 2的設定,就在之前講到的Iterations這篇裡面 )。

然後我們可以點選倒三角形,來將Product Backlog移到想要的Sprint裡面。

image

至此,我們就完成了初步的Product Backlog新增與排程。

2011年12月18日

點課幫 Developer Party 11-1218活動展開!

活動順利完成!

這一次非常感謝好友們的支援和幫忙,才能讓此活動順利完成,過程中碰到了許多預料不到的事情,還好有大家的幫忙,才能讓小弟在這次度過難關,也讓小弟在舉辦的過程中學習到很多東西,在此感謝各位!

第一堂課 迅速上手!! ASP.NET MVC 系列課程 (二) 投影片下載

SONY DSC

這次這個系列也算暫時告一個段落與結束了,雖然比較重要的東西濃縮在兩次講完,但其實還有滿多東西沒有提到的,但無論如何,這是一個入門,希望讓未來想寫MVC的人,大概有個概念,可以比較輕易地進入!

第二堂課 Android手機開發-Mobile App:使用PhoneGap與手機應用程式框架 ( Jim Blog網址 )

SONY DSC

PhoneGap算是很新的主題,Jim也講得很好喔,讓大家了解PhoneGap的好處缺點,另外,也提到了jQuery Mobile的部分,我相信來聽這堂課的人,一定收穫非常多!

--我是舊資訊分隔線--

第四次的活動展開!

延續上次的ASP.NET MVC主題,這次小弟持續為大家帶來ASP.NET MVC的第二階段,讓大家能持續的學習喔!如果上次上課有不清楚的地方,這次也提供上課前的前提回顧的服務!有需要的可以提早通知喔。

此外,受到大家熱烈期待的行動裝置開發課程,這次又回來了,這次是由之前上課頗受大家好評,且擁有多年Android手機開發經驗的講師Jim,來為大家介紹如何使用PhoneGap來寫一次程式碼就讓不同平台的手機執行,相信大家絕對可以學到許多不一樣的東西!

最後,有鑑於上次大家反應還是想吃吃喝喝,所以這次回歸到外面茶店舉辦,也讓大家聽課之餘可以填飽肚子,讓頭腦充實,肚子也充實喔!

點課幫 Developer Party 1218 - 邊吃邊喝邊學習!

( 費用一人約200,依據人數而定 )

時間 : 12/18 12:30 進場,13:00 ~ 17:00 對於ASP.NET MVC有興趣的可以12:00提前到場。
地點 : 台中市公益路二段106號 (無為草堂)
課程大綱:( 每場70分鐘 )
1.迅速上手!! ASP.NET MVC 系列課程 (二) - Sky
2.Android手機開發-Mobile App:使用PhoneGap與手機應用程式框架 – Jim


檢視較大的地圖

2011年12月17日

WPF - Attached Property 深入探討

此篇延續上一篇Dependency Property內容,上一篇談到最後,提到了一個初次進入WPF或是Silverlight時,會覺得很奇怪的地方,例如說設定DockPanel的上下左右對齊,通常我會覺得說,至少會這樣寫 ( 小弟膚淺的認知. )。

<DockPanel xxx=left>
    <Button/>
</DockPanel>

但在WPF裡面,卻是這樣寫。

<Button DockPanel.Dock="Top">

程式碼的話,會這樣寫。

DockPanel.setDock(btn,Dock.Top);

沒錯,並沒有看錯,呼叫一個靜態類別DockPanel,然後使用靜態方法setDock(),裡面第一個參數是要設定位置的控制項,第二個參數則是利用Dock的列舉型別來設定上下左右。

老實說,我第一次看到,會覺得很詭異,為什麼會用這麼詭異的方式進行設定呢?也完全顛覆了我之前的認知( 所以說,我很膚淺嘛~~ )。

Attached Property

中文翻譯叫做附加屬性;既然Attached Property會放在Dependency Property後面講,大家應該就可以猜的到了,會用那麼奇怪的寫法,其實這個的原始技術還是在Dependency Property。

首先我們先來看,實際的DockPanel原始碼,其實內容和之前講的Dependency Property類似,比較不同的是,這裡的DockProperty是使用DependencyProperty.RegisterAttached來進行註冊的,此外,get和set裡面,都有傳入UIElement進來,簡單的說,就是使用傳進來的UIElement來呼叫SetValue和GetValue,而非是呼叫DockPanel的SetValue和GetValue。

public class DockPanel : Panel
{
    public static readonly DependencyProperty DockProperty;
    public static void SetDock(UIElement el,Dock dck)
    {
        el.SetValue(DockProperty,dck);
    }
    public static Dock GetDock(UIElement el)
    {
        return (Dock) el.GetValue(DockProperty);
    }
}

那這樣代表甚麼,記不記得前面Dependency Property有提到,利用SetValue會將資料存到某個Collection裡面,所以簡單的說,我們在DockPanel設定了靜態方法SetDock和GetDock,但實際上,上下左右的設定,會存放到,由SetValue第一個參數傳入進去的UIElement元件裡面去。而這種感覺,就像是我們在DockPanel設定了DockProperty這個屬性,但實際上,此屬性附加到了真實會用到的控制項上面,所以才會有Attached Property之稱。

Attached Property的一些特點

前面有提到,既然不是呼叫DockPanel裡面的SetValue和GetValue,所以我們可以發現到,其實時要實踐attached property的類別是不需要延生自DependencyObject的!,當然要實際SetValue和GetValue的類別還是要延生自DependencyObject。

其次,其實前面寫到這樣的設定上下左右。

DockPanel.SetDock(btn,Dock.Top)

懂得原理後,其實我們也可以這樣寫,道理是相通的。

btn.SetValue(DockPanel.DocProperty,Dock.Top)

所以這兩種基本上是一樣的,也因此,Attached Property算是Dependency Property的一種延伸型態,

為什麼使用Attached Property

要提到這個,又要講古了,以前的Win Forms程式可能會這樣寫。

btn.Dock = Dock.Top

而使用這種方法,最大的問題就是,如果btn沒有在Dock下面,那這個屬性就等同於沒有用,所以後來WPF才實作出這種有彈性的天才作法 ( 老實說,真的很厲害… ),所以以後要寫WPF,要設定上下左右,就不會覺得奇怪啦..

參考資料

2011年12月15日

WPF - Dependency Property 深入探討

一直以來,我都認為Flex和WPF ( Silverlight ) 的架構、模式都差不多,反正就是利用XML進行視覺的排版,然後後面有邏輯程式進行處理,然後一堆類似的容器、Control、和事件傳遞模式。

沒錯,後來深深的發現,我錯了QQ,WPF的架構比Flex的架構深的多,並不是說Flex不好,而是深入地去瞭解WPF後,發現兩者的差異其實很大的,其中一個就是Dependency Property。

Property

談Dependency Property之前,我們先談談Property,中文稱之為屬性,其實簡單的理解,就例如TextBlock的FontSize,裡面存放著字型的大小,而這種程式碼在XAML裡面可能會這樣寫。

<TextBlock FontSize="12"/>

簡單易了解吧,那如果是用Code的方式,可能就會是這樣。

TextBlock textBlock = new TextBlock();
textBlock.FontSize = 12;

也滿簡單的,而且,我相信大家一定也都很清楚,但真的是這樣子嗎?讓我們繼續看下去。

Property的延續

下面是一個WPF的Tree,反正就是簡單的Window下面有DockPanel、StackPanel容器,然後下面又有Button。

image

這時候,如果只有在Window下設定FontSize = 12,其他的元件都沒設定FontSize = 12,各位猜,字型會多大多小?

答案當然是全部都是12,可想而知,下面的元件會延續根的設定,除非元件自己有設定FontSize。

解析XML

最近在處理一個案子,內容是將XML格式的內容,視覺化出來,其實並沒有想像中的那麼簡單,如上面的那個例子,如果XML最外圈有設定FontSize,內圈都沒有設定FontSize,但是內圈的FontSize若沒有設定,就要沿用外圈的FontSiz,這種程式碼要怎麼寫!?

好吧,愚蠢的我,當然就是用迴圈的方式,去裡面一個一個比對,然後再針對每個內容進行if的判斷處理。

如果只顯示一次那還好,但如果要在Run Time時,動態改變字型大小,然後又要調整每個元件的大小,呵呵呵…想翻桌了= =。

WPF Dependency Property

當然,弄出WPF的團隊,都是神人,自然不會用我這種愚蠢的方法,所以他們用了一個Dependency Property ( 相依屬性 )的架構來解決這種問題,在看Dependency Property之前,我們先看看,以前的Property是怎樣寫的。

private double fntsize;
public double FontSize
{
    get { return fntsize; }
    set { fntsize = value; }
}

老實說,我也是這樣寫的,然後如果FontSize改變的話,可能就去呼叫FontSizeChanged事件…然後…然後…反正就是很麻煩。

所以WPF使用了Dependency Property,Dependency Property允許以一般的方式進行大部分的通知;那Dependency Property怎樣寫呢?

第一步就是先用靜態類別定義一個DependencyProperty型態的欄位( C#裡面有欄位這個名詞,不清楚的話可以參考這裡,但其實就是定義一個變數,但沒有提供存取的方法,而在C#裡面,屬性這個名詞,是有提供存取的方法,這裡特別強調欄位的原因,是因為MSDN裡面,類別的成員,會區分屬性和欄位這兩個名詞,為了方便查找和避免錯亂,所以這裡我就稱為欄位。 ),此外,要注意的一點,這邊設定FontSize這個Dependency Property,那就必須在後面加上Property,所以加上後的欄位名稱就稱為FontSizeProperty。

public class Control : FrameworkElement
{
...
    public static readonly DependencyProperty FontSizeProperty;
...
}

當然,並非這樣就結束了,這可是readonly耶,而且目前FontSizeProperty裡面也沒任何東西,所以我們必須要在靜態建構子中,給FontSizeProperty參照一個物件;我們使用DependencyProperty的靜態方法Register來參照一個物件,而裡面需要帶一些參數,第一個參數是和此DependencyProperty關聯的Property名稱,第二個是型別,第三個是誰註冊,其實還有第四個參數,這部分後面再講。

static Control()
{
    FontSizeProperty = DependencyProperty.Register("FontSize", typeof(double), typeof(Control));
}

到這邊,並沒有結束,雖然我們有這個欄位,但我們並沒有可以存取的方法,所以接下來我們要寫方法來存取;這裡的set和get大家應該都清楚了,但是SetValue和GetValue又是啥?其實在WPF裡面,UIElement是繼承DependencyObject這個物件而來,而DependencyObject又是繼承DispatcherObject(抽象)而來,而SetValue和GetValue就是從DispatcherObject而來的,所以我們可以直接呼叫使用。( 換言之,如果要實作Dependency Property,就必須繼承於DispatcherObject之下,不過這樣也很合理,畢竟,這是WPF的一個機制 )。

public string FontSize
{
    set { SetValue(FontSizeProperty, value ); }
    get { return (double) GetValue(FontSizeProperty); }
}

SetValue有兩個參數,第一個就是剛剛定的欄位( FontSizeProperty ),第二個就是要存進去的值,而GetValue,其實就是取出來,這樣就完成了Dependency Property程式碼撰寫。

其實,WPF裡面幾乎都是使用Dependency Property機制來處理,最前面講到的TextBlock的FontSize,其實也是使用Dependency Property來處理的。

Dependency Property機制

說到這裡,我相信應該還有人有一堆問題,例如說,他們是怎樣傳遞的,以此圖來說,如果除了Window以外,都沒有給FontSize大小,後面的元件要怎樣知道Window所設定的FontSize?

image

這邊,小弟我取用許薰尹老師文章的其中一個圖,如右邊所示,沒錯,WPF的屬性系統 ( 也就是Dependency Property機制 )會自動的延續 ( 繼承 ) 最上方的節點元件。

image

那這代表甚麼?其實WPF的Dependency Property會資訊存到某個Collection裡面,並自動進行處理,所以我們只要確定底下的節點,都有定義Dependency Property,那Dependency Property就會自動地去處理這些細節,我們完全可以不用管。

Dependency Property的設定!?

前面有談到,在Register時,還有第四個參數和第五個參數,其實第四個參數是用來設定一些Dependency Property的細節,例如是否要延續父層的屬性、是否會影響尺寸、預設值等等;而第五個參數是當值改變的時候,要呼叫的方法。

FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.AffectsMeasure = true;//是否會影響Element Size大小
metadata.Inherits = true;//是否延續上層
FontSizeProperty = DependencyProperty.Register("FontSize", typeof(double), 
    typeof(Control), metadata, ValidateFontSize);

然後這是值改變時,呼叫方法的寫法。

static void ValidateFontSize(DependencyObject obj,DependencyPropertyChangedEventArgs args)
{...}

基本上,這就是整個Dependency Property的架構,利用Dependency Property,WPF就變得更簡單,也更容易去處理。

下一篇,我們來談談附加屬性,也就是一開始接觸WPF,讓人匪夷所思的DockPanel.Dock(xxx,Dock.Right);這種寫法。

參考資料

WPF相依屬性與附加屬性