顯示具有 WPF 標籤的文章。 顯示所有文章
顯示具有 WPF 標籤的文章。 顯示所有文章

2014年12月26日 星期五

WPF 樣式和範本(一)Style 的使用

在 WPF 中,Style 的作用是透過屬性(Property)來自訂控制項的外觀。當然,Style 的功能並不是只有自訂控制項外觀那麼簡單,其最大的作用是可以統一 xaml 頁面上的控制項外觀,舉個簡單例子,如果有一個小計算機程式,其按鍵分為數字鍵和功能鍵,按照一般作法是建立 Button 物件後設定其外觀顏色、字型大小、間距等等屬性,但有了 Style 就可以統一這些按鍵的屬性(Property)。實作如下:
  • xaml

<Window x:Class="SimpleDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="117" Width="133">
    <Window.Resources>
        <Style x:Key="myButton" TargetType="{x:Type Button}">
            <Setter Property="Width" Value="30"/>
            <Setter Property="Height" Value="30"/>
            <Setter Property="Background" Value="White"/>
            <Setter Property="Foreground" Value="Green"/>
            <Setter Property="Margin" Value="2"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <Button Style="{StaticResource myButton}" Content="1"/>
            <Button Style="{StaticResource myButton}" Content="2"/>
            <Button Style="{StaticResource myButton}" Content="3"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Button Style="{StaticResource myButton}" Content="4"/>
            <Button Style="{StaticResource myButton}" Content="5"/>
            <Button Style="{StaticResource myButton}" Content="6"/>            
        </StackPanel>
        <!--                 以下省略                            -->
    </StackPanel>
</Window>


  一開始把 Style 程式區塊放在最上層 Window 中的 Resources 區塊中,在 Style 區塊中建立一個以供 Button 物件在套用時可識別的 x:Key,接下來再加入 Setter Property 屬性及 Value 值,必須注意的是,Property 的設定必須是物件的依存屬性(Denendency Property)。

  接下來在第 2 層 StackPanel 中陸續加入 Button 物件,並將 Button 的屬性 Style 繫結到 Window.Resource 區塊中 key 為 myButoon 的 Style。

  值得注意的事,在 Window.Resources 區塊中的 Style,如果不加 Key,那麼會是怎樣的結果,結果會是在此 xaml 頁面中的 Button 物件屬性將會統一(在未加入其它 Style 及未設定 Button 物件 Style 屬性前提下)。換個角度來看,如將 Style 加入在 StackPanel.Resources 區塊中,那麼結果將只會影響到 StackPanel 區塊中的 Button 物件,如下:


    <StackPanel Orientation="Horizontal">
        <StackPanel.Resources>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Width" Value="30"/>
                <Setter Property="Height" Value="30"/>
                <Setter Property="Background" Value="White"/>
                <Setter Property="Foreground" Value="Green"/>
                <Setter Property="Margin" Value="2"/>
                <Setter Property="FontSize" Value="14"/>
                <Setter Property="FontWeight" Value="Bold"/>
            </Style>
        </StackPanel.Resources>
        <Button  Content="1">
        </Button>
        <Button  Content="2"/>
        <Button  Content="3"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <Button  Content="4"/>
        <Button  Content="5"/>
        <Button  Content="6"/>            
    </StackPanel>
    <!--                 以下省略                            -->
</StackPanel>

  如果要把 Background 顏色從純色改為漸層,那就須將 Value 拿掉,加入 Setter.Value 區塊,並將漸層加入區塊中,其演示如下:


<Style TargetType="{x:Type Button}">
    <Setter Property="Width" Value="30"/>
    <Setter Property="Height" Value="30"/>
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                <GradientStop Color="Pink" Offset="0"/>
                <GradientStop Color="White" Offset="0.5"/>
                <GradientStop Color="Pink" Offset="1"/>                                
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Foreground" Value="Green"/>
    <Setter Property="Margin" Value="2"/>
    <Setter Property="FontSize" Value="14"/>
    <Setter Property="FontWeight" Value="Bold"/>                    
</Style>








2014年12月25日 星期四

WPF Binding (二) DataBinding 資料繫結

在 Wpf 中,繫結來源除了控制項之間的繫結外,在程式中的任何物件、集合都可作為繫結來源。以下用一個學生物件來展現物件與控制項之間的繫結。
  • c# Student 類別

public class Student
{
    public string Name { get; set; }
    public int Number { get; set; }
}





  • xaml
<Window x:Class="SimpleDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SimpleDataBinding"        Title="MainWindow" Height="124" Width="174">
    <Window.Resources>
        <local:Student x:Key="student"
                       Name="王小明"
                       Number="9"/>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="學生姓名:" Margin="5"/>
            <TextBlock Text="{Binding Source={StaticResource student}, Path=Name}" Margin="5"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="座號:" Margin="5"/>
            <TextBlock Text="{Binding Path=Number,Source={StaticResource student}}" Margin="5"/>
        </StackPanel>
    </StackPanel>
</Window>
  要把類別 Student 加入到 xaml 中,一開始是在 Window 標籤中宣告 Student  物件命名空間的參考 local,local 是自訂名稱,而後面要再連接 SimpleDataBinding 的 NameSpace,最後在 Window.Resource 標籤中加入Student 物件的邏輯資源。以上 xaml 的寫法是使用 Static Resources 來處理資料繫結,還可使用DataContext 來處理資料繫結。如下:


<Window x:Class="SimpleDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SimpleDataBinding"
        Title="MainWindow" Height="124" Width="174">
    <Window.DataContext>
        <local:Student Name="王小明"
                       Number="9"/>
    </Window.DataContext>
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="學生姓名:" Margin="5"/>
            <TextBlock Text="{Binding Path=Name}" Margin="5"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="座號:" Margin="5"/>
            <TextBlock Text="{Binding Path=Number}" Margin="5"/>
        </StackPanel>
    </StackPanel>
</Window>




  以上的 xaml 變動不大,把原本 Window.Resources 標籤換成 Window.DataContext 標籤,而在控制項資料繫結方面,將原本 Source 屬性給拿掉。



當然也有個疑問,是否可以在 local:Student 標籤中不給屬性 Name 和 Number 值呢?當然是可以的,例如直接在 Student 類別中的建構子給予 Name 和 Number 一個值,或在另一個 StudentInfo 類別中建立一個 Student 物件。





  • C# Student.cs


public class Student
{
    public string Name { get; set; }
    public int Number { get; set; }

    public Student()
    {
        this.Name = "王小明";
        this.Number = 9;
    }
}





  • C# 從 StudentInfo 建立 Student 物件


public class StudentInfo
{
    public Student student;

    public string Name
    {
        get { return student.Name; }
        set { student.Name = value; }
    }
    public int Number
    {
        get { return student.Number; }
        set { this.student.Number = value; }
    }

    public StudentInfo()
    {
        this.student = new Student();
        this.student.Name = "王小明";
        this.student.Number = 9;
    }
}





  • xaml 變更 DataContext 繫結來源


<Window.DataContext>
    <local:StudentInfo/>
</Window.DataContext>

以上寫法是把 Student 物件放在 Window.DataContext 標籤中,如果單純使用程式碼的寫法,則如下所示:



  • C#

namespace SimpleDataBinding
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Student student = new Student() { Name = "王小明", Number = 9 };
            this.DataContext = student;
        }
    }

    public class Student
    {
        public string Name { get; set; }
        public int Number { get; set; }
    }


}


  • xaml

<Window x:Class="SimpleDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="117" Width="133">

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="學生姓名:" Margin="5"/>
            <TextBlock Text="{Binding Path=Name}" Margin="5"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="座號:" Margin="5"/>
            <TextBlock Text="{Binding Path=Number}" Margin="5"/>
        </StackPanel>
    </StackPanel>
</Window>



  Static Resources 和 DataContext 的區別在於,當有多個目標的繫結來源都來自同一個資源時,使用 DataContext 無非是最好的作法,既可避免造成程式碼冗長,也容易維護。