[WPF]設置背景色


程序效果

最終得到程序的運行效果如圖。拖動Slider可以使按鈕的背景色出現相應變化。

需求分析和架構設計

如果是你,接到了這樣的一個程序設計要求,會怎樣思考?
第一步當然是需求分析啦。這個程序相對簡單,需要分析的主要是各個控件之間的數據聯系。這主要體現在Slider, Textbox和Button間的同步關系上:
拖動Slider的滑塊,要求TextBox里的數值也要變化,同時Button的背景色也要發生相應變化。改變TextBox里的值,滑塊的位置和Button的背景也要做相應調整。
一個習慣於WinForm的同學就會有很自然的想法——處理消息(.NET表現為事件)唄。對Slider滑塊的滑動這個事件,設置一個EventHandler,以更新Textbox的Text屬性和Button的Background屬性。對於Textbox.Text的更改這個事件,設置一個EventHandler,更新Slider的Value屬性和Button的Background屬性。
很好。下面我們就來看一下在WPF中,思維可以變得如此不同而簡單。

實現過程

第一步自然是創建工程。首先在Visual Studio 2008下,新建一個工程,選擇Visual C#里面的WPF Application即可。

稍等片刻就可以看見一個工程被創建,同時默認的窗體設計文件Windows1.xaml被顯示出來了。注意雖然XAML中可以像MFC那樣用圖形化的方式放置控件,但是由於XAML的功能太強大,圖形化界面很難完全表達,因此在目前的版本中主要還是采用代碼的方式進行界面設計。不過微軟已經放風說在Visual Studio 2010中這樣的情況會加以改善。
第二步是設計UI。首先在XAML代碼中<Grid></Grid>間插入:

復制代碼
<Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
<RowDefinition /> </Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
復制代碼

這一段代碼主要是將整個界面唰唰切成5行3列一共15個大塊,在設計界面中可以很清楚的看到(如下圖)。其中最左邊和最右邊這兩列固定為50像素,中間那一列是寬度可變的。

下面就要往里面放控件了。在</Grid.ColumnDefinitions>和</Grid>間繼續加入以下代碼:

<TextBlock Grid.Column="0" Grid.Row="0">Red</TextBlock> <Slider Grid.Column="1" Grid.Row="0"/> <TextBox Grid.Column="2" Grid.Row="0"/>

這是在第一行的第一個格子里放了一個TextBlock控件,用來顯示那個Red。然后在同一行的第二個格子里放了一個Slider,第三個格子里放了一個TextBox。現在設計界面是這樣的:

看起來好丑哦。沒關系我們來修飾一下。
首先窗口太大了,把XAML文件中第四行中Window1的Height改成200先。然后每個控件把格子占得滿滿的,影響美觀。在各個控件中加入Margin="5",比如Slider控件的代碼現在看起來應該是這樣的:
<Slider Grid.Column="1" Grid.Row="0" Margin="5"/>
這樣就使得空間和格子間有一定的間距,看起來舒服一點。
然后將各個控件的垂直對齊方式設為中間對齊,加入VerticalAlignment="Center"即可。好的,現在蠻漂亮的了。

代碼看起來應該是這樣:

<TextBlock Grid.Column="0" Grid.Row="0" Margin="5" VerticalAlignment="Center">Red</TextBlock>
<Slider Grid.Column="1" Grid.Row="0" Margin="5" VerticalAlignment="Center"/>
<TextBox Grid.Column="2" Grid.Row="0" Margin="5" VerticalAlignment="Center"/>

下面我們來加入其余三個TextBlock, Slider和TextBox。分別代表Green, Blue, Alpha值。將以上代碼復制粘貼三份即可。注意每一行都要相應修改Grid.Row值。第二行為1,以此類推。不要忘了把后面幾行TextBlock里的Red改成相應的Green, Blue等等哦。現在界面看起來像這樣:

最后需要在最后一行加入一個Button。在</Grid>前添加如下代碼:

<Button Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="4" HorizontalAlignment="Center" Width="100" Margin="5"> <Rectangle Width="10" Height="10" Fill="Red"/> </Button>

很容易看懂這是說要添加一個寬度100像素,水平中央對齊,在第5行的按鈕。按鈕的內容是一個長寬各為10,紅色的方形。只是要注意Grid.ColumnSpan="3"表示這一個控件將占用3列的空間。

再把Window1的Title改成ColorChange。至此UI的設計就結束了。如下圖。

呼,界面設計說起來還是比較繁瑣的。終於進入WPF強大的地方了。首先是界面設計的時候注意到了嗎?Button的內容可以是一個方塊誒!如果我告訴你還能是其他控件比如是一個slider外加一個TextBox呢?就像這樣:

要是在MFC里面還不要搞死人。最簡單的情況是通過改CButton的bitmap來實現在按鈕上顯示圖片。就算只想在里面嵌入一個Slider,就首先要繼承CButton類,然后廣大人民充分發揮聰明才智吧,拼死拼活總算搞出來一種控件叫做CSliderButton。然后一拍腦袋,哎呀我搞錯了,其實我想嵌入一個TextBox的。好吧,大返工……但是在WPF里如此簡單,我們要做的僅僅是把<Rectangle />換成其他控件就好了,比如<Slider />,或者另一個有復雜結構的<Grid>。是不是很神奇?
還有我們上面進行的UI設計相對MFC來說繁瑣很多,但是也要強大很多。這主要表現在窗口的大小被改變時。一個MFC對話框程序,如果沒有經過特別精心的設計的話,一旦窗口大小被拖動或者最大化,一坨控件還像原來一樣分布,擁堵在左上角,唉……但是上面設計出的WPF的程序就不會,控件仍然會均勻分布在窗口中。(你可以自己試試看,如果覺得還是不夠完美可以自己想想怎樣再改動呢?)

下面進入消息處理階段了,如果還可以這樣稱呼的話。第一步要把Slider和TextBox中的內容關聯起來。為了以下程序設計的方便,我們必須要先給各個控件起個名字。在第一行的Slider里面添加Name屬性,叫它ColorSliderR好了!也就是說,在<Slider ... />中加入Name="ColorSliderR"
同樣的,我們給剩下各個slider起名叫做ColorSliderG/B/A。把那個Button稱作MainButton。
然后要調整Slider的屬性,否則沒有應用價值。在各個Slider的代碼里加入Maximum="255" Minimum="0" Value="255"。這表示滑塊到達最右邊的時候表示255,最左邊表示0,初始值在255。那么Slider的代碼看起來應該是這樣的:

<Slider Grid.Column="1" Grid.Row="0" Margin="5" VerticalAlignment="Center" Maximum="255" Minimum="0" Value="255" Name="ColorSliderR"/>

 

睜大眼睛啦!WPF神奇的地方又來啦!什么消息處理,這么麻煩,走開!不就是同步嘛,把TextBox和Slider綁上不就得了。好的。在4個<TextBox ... />中加入代碼Text="{Binding Path=Value, ElementName=ColorSliderR}",注意ElementName的值要根據各個控件改動哦。這樣就把兩個控件Bind起來了。運行一下看看:

成功啦!簡單不?嘖嘖,還帶小數點的,真牛X。注意,如果想要通過改變文本框的內容來改變滑塊位置的話,需要在輸入完畢后切換一下焦點,也就是隨便點一下本窗口內的其他地方改動才會生效。
真么快?都到第四步了。下面就要改變背景色啦。XAML固然強大,但光玩控件間的綁定沒意思,咱辛辛苦苦學的for啊while啊不都沒用了嘛。這下咱換種方式。把XAML和后台代碼綁定起來。
為了實現這個目標,先要做一個橋梁——在XAML和后台代碼間溝通的橋梁。終於輪到C#上場了,人家都急死了。右擊XAML設計界面,單擊View Code打開Window1.xaml.cs。啊,終於看到熟悉的using了,激動死了激動死了。
在public partial class Window1這個類的后面,也就是這個類的}的后面,相當於跟這個類並列的地位,不要搞錯了啊,插入一個類,代碼如下:

復制代碼
public class SliderCommunicator: INotifyPropertyChanged
{ // INotifyPropertyChanged Members
  public event PropertyChangedEventHandler PropertyChanged;
  protected void Notify(string propName)
  {
    if (this.PropertyChanged != null)
    {
     PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
  }
  int sliderValue = 255;
  public int SliderValue
  {
    get { return sliderValue; }
    set {
        sliderValue = value;
        Notify("SliderValue");
       }
      }
   }
復制代碼

學過C#的對這個應該很熟悉,標准的事件處理方法。大意就是這個類里面有一個屬性SliderValue。它一旦被更改了就會大叫:老大我被人動啦!然后——當然很多人根本不睬他,只有他的老大聽到了就會過來看看並作出相關操作。這是C#針對消息處理作出的語言內部的支持。

還有,不要忘了在最前面那一坨using的最后插入一句

using System.ComponentModel;

這是為了提供對事件處理的支持。

有了這個類,橋架起來了,綁定就好辦了。當然一個控件應該是和代碼中的一個對象綁定而不是和一個類綁定,所以叫你有面向對象程序設計基礎呢,否則對象啊類啊還不把你繞昏掉。對象自然只能在Window1類中定義。好的,在類中(具體位置隨便在哪,只要這個類里面就好)加入

SliderCommunicator sliderCR, sliderCG, sliderCB, sliderCA;

然后搞個函數把他們初始化一下,整個Window1類看起來應該是這樣的:

復制代碼
public partial class Window1 : Window
{
  SliderCommunicator sliderCR, sliderCG, sliderCB, sliderCA;
  public Window1()
  {
    InitializeComponent();
  }
  void InitDataBinding()
  {
    sliderCR = new SliderCommunicator();
    sliderCG = new SliderCommunicator();
    sliderCB = new SliderCommunicator();
    sliderCA = new SliderCommunicator();
  }
}
復制代碼

嗯嗯,很好,下面我們就可以把XAML和C#綁起來了。兩步走,第一步,改改InitDataBinding函數,改成這樣:

復制代碼
void InitDataBinding()
{
  sliderCR = new SliderCommunicator();
  ColorSliderR.DataContext = sliderCR;
  sliderCG = new SliderCommunicator();
  ColorSliderG.DataContext = sliderCG;
  s liderCB = new SliderCommunicator();
  ColorSliderB.DataContext = sliderCB;
  sliderCA = new SliderCommunicator();
  ColorSliderA.DataContext = sliderCA;
}
復制代碼

意思就是把每個Slider控件和相應的對象綁起來。

第二步,回到XAML設計界面,在每一個<Slider ... />里把原來的Value="255"改成Value="{Binding Path=SliderValue}"
這是更進一步具體地說,把這個Slider的Value屬性和相應的那個對象的SliderValue綁定起來。
好吧現在看看發生了什么事情呢。當Slider的滑塊一被拖動的時候,WPF就會自動更新綁在一起的SliderCommunicator對象的Value屬性,然后它就會大叫起來老大我被人動啦!但是現在還沒人理他呀,沒用呢。沒關系,我們給他造出一個老大來。
首先在Window1中定義函數

復制代碼
void ChangeMainButtonColor(object sender, PropertyChangedEventArgs e)
{
  SolidColorBrush NewColor = new SolidColorBrush();
  NewColor.Color = Color.FromArgb((byte)sliderCA.SliderValue, (byte)sliderCR.SliderValue, (byte)sliderCG.SliderValue, (byte)sliderCB.SliderValue);
  MainButton.Background = NewColor;
}
復制代碼

還記得那個Button其實叫做MainButton嗎?這個函數就是改變Button背景值的。下面讓它做個實實在在的老大。

在InitDataBinding的最后部分加入語句

復制代碼
sliderCR.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
sliderCG.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
sliderCB.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
sliderCA.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
復制代碼

好了。現在SliderCommunicator一叫Button就會跑過來,然后把自己的背景改掉了。大功告成!運行看看:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM