2012年12月25日 星期二

WPF DataBinding 資料繫結簡介

我想有兩種狀況會有這個需求。

1.如果你需要資料跟UI元件能即時隨時的互動,隨著資料改變,UI的顯示就跟著變(或者反向),這時候,你就需要他。

2.如果你需要在Thread或Task中顯示目前進行的狀況或是任何資訊在某種UI元件上,比方Label, TextBlock,為了避免跨執行緒UI操作這種神秘又討厭的Exception,而你又不想為此作Delegate,這時候,你也可以靠他幫助。


在WPF上的作法有兩種,一種是把Bnding寫在 XML 裡,一種是寫在C#程式裡,差異不大,因為最後資料的顯示也都用程式在控制居多。

首先,建立一個WPF 應用程式專案,然後在視窗上放一個按鈕、一個TextBlock、一個TextBox。名稱Name分別取為Btn_Bind、TxtBlk_Bind、TxtBx_Bind。位置隨便你放,能看得到就好了。

接下來,在程式當中,新增一個繼承INotifyPropertyChanged的Class,並且給他一個Member(當然,如果你有多個元件要跟多組數值作Binding,這裡就可以有多個Member),固定寫法如下,當Member要寫入新值,在set當中呼叫OnPropertyChanged(),他會產生PropertyChangedEventHandler 的事件,因此可讓UI可以知道該更新顯示了。


        public class MyData : INotifyPropertyChanged
        {
            private string m_TextMsg;
            public string TextMsg
            {
                set
                {
                    if ( m_TextMsg != value )
                    {
                        m_TextMsg = value;
                        OnPropertyChanged( "TextMsg" );
                    }
                }
                get
                {
                    return m_TextMsg;
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged( string propertyName )
            {
                if ( PropertyChanged != null )
                {
                    PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
                }
            }
        }



另外準備好按鈕的事件內容
        private void Bind_Click( object sender, RoutedEventArgs e )
        {
            m_MyData.TextMsg = "New Value";
        }



然後在CS檔中宣告一個全域變數,把你剛剛的INotifyPropertyChanged類型的Class宣告好

        private MyData m_MyData ;

然後在程式進入點函式中加入底下,產生物件實體與給予初始值
            m_MyData = new MyData();
            m_MyData .TextMsg = "Origin";



以上都準備好之後,開始進行Binding




第一種方法:在XML加入Binding 片段

XML會變成類似底下這樣:

<TextBlock x:Name="TxtBlk_Bind" HorizontalAlignment="Center" Margin="134,130,136,140" TextWrapping="Wrap" VerticalAlignment="Center" Height="50" Width="247" FontSize="20" Text="{Binding Path=TextMsg }" TextAlignment="Center"/>
        <TextBox x:Name="TxtBx_Bind" HorizontalAlignment="Left" Height="44" Margin="134,210,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="248" FontSize="20" Text="{Binding Path=TextMsg }"/>
        <Button x:Name="Btn_Bind" Content="改變數值" HorizontalAlignment="Left" Height="37" Margin="134,62,0,0" VerticalAlignment="Top" Width="99" Click="Bind_Click"/>



最後用程式告訴系統,你的Binding是哪一個


            TxtBlk_Bind.DataContext = m_BindData;
            TxtBx_Bind.DataContext = m_BindData;


(能不能把上面兩段寫成XAML呢?其實是可以的,可是,寫來頗複雜,而且還不知道要怎麼讓CS引用這個變數)


如此,你的TxtBlk_Bind跟TxtBx_Bind兩個元件就跟m_BindData 內的TextMsg 有了互動
不相信?你可以按下按鈕,就會看到TxtBlk_Bind跟TxtBx_Bind元件都變成了"New Value",而如果你在TxtBx_Bind輸入任何文字,然後按下[Tab]鍵,就可以看到TxtBlk_Bind也會跟著變成你輸入的東西了。(這是因為TxtBx_Bind輸入的數值會同步變更BindData內的TextMsg 數值,然後在同步更新到TxtBlk_Bind元件。




第二種方法:完全在程式中完成Binding

XML不用改,只要在程式當中加上底下四行:


            Binding BindingTxtBlk = new Binding() { Source = m_MyData , Path = new PropertyPath( "TextMsg" ) };
            TxtBlk_Bind.SetBinding( TextBlock.TextProperty, BindingTxtBlk );

            Binding BindingTxtBx = new Binding() { Source = m_MyData , Path = new PropertyPath( "TextMsg" ) };

            TxtBx_Bind.SetBinding( TextBox.TextProperty, BindingTxtBx );







太棒了,對吧!
我喜歡第二種,因為不用動到XML,感覺也挺直覺的。

2012年12月21日 星期五

Word2007插入 頁碼/總頁碼


在Word2007插入總頁碼,對很多已經熟悉Word2003的人來說,反而不知道怎麼作了,通常會查詢到的作法,都是插入頁碼之後,改設定功能變數。今天介紹一個很簡單的方法,其實「插入」、「頁碼」、「頁面底端(或頂端或邊界都可)」然後會選擇樣式,秘密就藏在這些樣式中,其中有一組「頁 X / Y 」名稱叫做粗體數字1、粗體數字2、粗體數字3。選這三個其中一個就行了。

2012年12月20日 星期四

String to byte[] 或 byte[] to String


這個很容易遇到,因為微軟把Framework做的很單純,很多傳輸都用Streaming,所以當資料要送出,會先將資料轉換成byte[]才能送出,而Json的作法又是把Class(List)轉換成字串,所以String跟byte[]之間互換會蠻常被使用到。



string要轉成byte[]:

byte[] byteArray = System.Text.Encoding.Default.GetBytes ( str );




byte[]要轉成string:

string str = System.Text.Encoding.Default.GetString ( byteArray );





Encoding.Default 這邊可以換成 ASCII, Unicode, UTF8....各種格式

2012年12月18日 星期二

改用比較好的架構來切割後端PHP與前端HTML


我在前幾天的兩篇文章中,提到一些關於網頁前端後端開發上的架構問題,

如何透過前端的Javascript得到Server端的PHP的變數數值


其實目的是為了引出這篇,我真正想要探究,想要知道的是一套好用、通用、實用或者大部分人怎麼用的架構,最近看了很多網路資訊、也請教了朋友之後,之後,覺得或許我找到了好的用法跟寫法,在此跟大家分享一下。


為了讓後端的資料能在前端因為資料不同而呈現不同的資訊、甚至是需要不同的UI編排,就會需要把PHP寫成多種分支。當某種資料時,則產生某種UI元件組合,當另外一種,則產生另外一種UI元件組合,如果資料型態有很多種,那這個PHP不就寫的又臭又難維護?尤其如果是採用 如何撰寫好看又好維護的PHP? 文章中第二種寫法的話,那個PHP會醜到讓維護的人想要殺人,所以第一個改進的方向,就是從第二種寫法,先改為第一種寫法,這是把UI跟邏輯資料分開的第一步,分開除了讓程式乾淨,之後不論是修改UI,或是PHP要換ASP也會容易些。


再來,可以把PHP更純化,只負責資料處理,而前端則是單純的HTML,透過JS來控制UI長相,但怎麼從JS拿到PHP的數值呢?之前會用 如何透過前端的Javascript得到Server端的PHP的變數數值 來達到,但是,更好一點的作法,是可以在JS透過Ajax的方式,向Server取得資訊,然後即時對前端的HTML產生變化。而其中的CSS除了美化UI之外,更可以方便透過跟JQuery的整合應用,來增加UI元件的Class屬性,比方:

$('#item').addClass('selected') 或 $('#item').removeClass('selected')。

一方面可達到顏色或外觀的控制,另一方面則是可以因此決定出哪些UI元件具備了什麼Class,然後用

$('#target').children( '.selected' )   $('.init_state:has(.selected)') 

來選到這些物件作一些控制,或是傳資訊到後端。如此一來,甚至有機會不用把HTML跟PHP寫在一起,可以分成不同檔案了呢。


架構上,大概就是朝這個方向去改,去設計,就對了。


參考資料:

2012年12月11日 星期二

如何撰寫好看又好維護的PHP?


工作這幾個月來,看同事的程式碼,慢慢對網頁程式有些瞭解了,前端用HTML拼湊我要呈現的東西,用CSS來讓畫面更有型,更美觀,用JavaScript讓網頁可以動態、根據不同狀況來產生不同網頁物件,或捕捉事件來控制網頁物件。而PHP用來在後端跟Server互動,比方根資料庫互動,或是跟檔案互動。而PHP最終目的也是要呈現資料給使用者看,所以PHP除了當純提供function,提供變數之外,本身也可以是個HTML,只是,他的副檔名必須是.PHP,這個概念,跟ASP差不多。

而程式跟HTML怎麼結合呢,目前看同事的寫法有兩種,一種是以HTML為主體,然後PHP是個區段,第二種,是PHP為主體,而HTML則透過ECHO方式吐出來,而前同事似乎比較喜歡第二種寫法(沒有批評的意思,只是從結果論)。

我個人喜歡第一種風格,原因是


1.以HTML為主體,可以直接把個PHP檔在Dreamwave開啟,看到確切的排版,如果以PHP為主體,你只能看到一片空白。


2.在瀏覽器進入Debug模式之後(通常按F12),如果用HTML為主體,則可以正常的單步看每行HTML的TAG有沒有寫錯,或是Script有沒有寫錯,或PHP有無正確(某些瀏覽器會直接看到PHP執行過後的數值而已),但是如果以PHP為主體,那麼ECHO所吐出的會變成一大行,根本就無法單步Debug了。




----------------方法一:HTML為主體----------------

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">


<?php
$user=$_GET['session'];
$session_path="/root/config/webaccess/httpd/".$user;
session_save_path($session_path);
session_start();
?>


<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <link rel="stylesheet" type="text/css" href="style/manage-style.css"/>
    <script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>
    <title>我的網頁</title>
</head>

<body>
    
    <div class="DivContent">    
        <label class="Lbl_Title">測試<?php  echo $session ?></label>
    </div>

</body>
</html>






----------------方法二:PHP為主體----------------


echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'


$user=$_GET['session'];
$session_path="/root/config/webaccess/httpd/".$user;
session_save_path($session_path);
session_start();



echo '<head>';
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>';
echo '<link rel="stylesheet" type="text/css" href="style/manage-style.css"/>';
echo '<script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>';
echo '<title>我的網頁</title>';
echo '</head>';

echo '<body>';    
echo '    <div class="DivContent">';
echo '        <label class="Lbl_Title">測試 $session</label>';
echo '    </div>';

echo '</body>';
echo '</html>';



我不是很明白,會有人喜歡第二種嗎?或是有什麼理由要寫成第二種呢?目前只覺得,除非為了省時間,偷懶XD