最近設計x程式社團的林星同學提到關於使用ObjectDataProvider來進行資料的繫結的方式,幫不上什麼大忙的我,只能寫些入門的小範例來看看能不能有所幫助,就透過這個小範例來讓有興趣的朋友們先對ObjectDataProvider有基本的認識吧!!
最近設計x程式社團的林星同學提到關於使用ObjectDataProvider來進行資料的繫結的方式,幫不上什麼大忙的我,只能寫些入門的小範例來看看能不能有所幫助,就透過這個小範例來讓有興趣的朋友們先對ObjectDataProvider有基本的認識吧!!
首先呢~請自行連結到MSDN上關於ObjectDataProvider的介紹看看先吧!!除此之外,MSDN上還有一個不錯的範例:How to: Bind to an Enumeration
如果有仔細看完MSDN的介紹,以及範例的內容,那應該對ObjectDataProvider有初步的了解了~
基本上,ObjectDataProvider的以下三個屬性是很值得拿來好好運用的喔!!
ObjectType:提供繫結資料的型別
MethodName:提供繫結資料的型別用來輸出資料的方法
MethodParameters:要傳給輸出資料的方法的參數
只要好好善用上面的三個屬性,就可以把之前很多得寫好幾行程式碼的東西,透過ObjectDataProvider,直接在Xaml裡面就做完喔!!暖身就到這邊告一段落啦!!
而今天要分享的範例呢,就如同文章標題所說的,要來透過C#在CodeBehind中改變ObjectDataProvider的資料來源!!讓我們先來看看實作出來的成品:
(*若無法正常瀏覽本文WPF版範例,煩請參考[Windows7]使用IE9、FireFox與Chrome瀏覽WPF Browser Application(.XBAP)的方式一文調整瀏覽器設定)
這個範例其實很簡單,我用C#先寫好兩個用來描述資料的簡單類別,分別為Member和Product,程式碼如下:
public class Member
{
public int Id
{
get;
set;
}
public string Name
{
get;
set;
}
public bool Sex
{
get;
set;
}
}
public class Product
{
public int Id
{
get;
set;
}
public string Name
{
get;
set;
}
public string OS
{
get;
set;
}
}
再來是兩個使用了上述兩個類別,可以透過呼叫裡面的方法,用來提供資料的類別:
using System.Collections.Generic;
using System.Collections.ObjectModel;
public class Members
{
private ObservableCollection<Member> _members = new ObservableCollection<Member>
{
new Member{ Id = 1 , Name = "Ouch Liu" , Sex = true },
new Member{ Id = 2 , Name = "Yuan Monkey" , Sex = false },
new Member{ Id = 3 , Name = "Bill Gates" , Sex = true },
new Member{ Id = 4 , Name = "Angela Baby" , Sex = false },
new Member{ Id = 5 , Name = "Wei Liu" , Sex = true },
};
public List<Member> GetFemales()
{
return _members.Where( m => m.Sex == false ).ToList();
}
public List<Member> GetMales()
{
return _members.Where( m => m.Sex == true ).ToList();
}
}
using System.Collections.Generic;
using System.Collections.ObjectModel;
public class Products
{
private ObservableCollection<Product> _products = new ObservableCollection<Product>
{
new Product{ Id = 1 , Name = "LG GW910" , OS = "WP7" },
new Product{ Id = 2 , Name = "SonyEricsson X10" , OS = "Android" },
new Product{ Id = 3 , Name = "HTC HD7" , OS = "WP7" },
new Product{ Id = 4 , Name = "iPhone 4" , OS = "iOS" },
new Product{ Id = 5 , Name = "Samsung Focus" , OS = "WP7" },
};
public List<Product> GetWindowPhones()
{
return _products.Where( p => p.OS == "WP7" ).ToList();
}
public List<Product> GetAndroidPhones()
{
return _products.Where( p => p.OS == "Android" ).ToList();
}
}
有了這四個類別之後,其實就可以在Xaml中直接透過ObjectDataProvider來呼叫Members.GetFemales()、Members.GetMales()或是Products.GetWindowPhones()、Products.GetAndroidPhone()這四個方法來取得資料,並進行繫結啦!!
不過我們要玩的不只是這樣,要在執行期動態的抽換資料的來源,就得在設定完ObjectDataProvider各個屬性之後,呼叫ObjectDataProvider.Refresh()方法,來看看上面的範例是怎麼寫的吧!!
<Page x:Class="Wpf_ObjectDataProvider.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf_ObjectDataProvider"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800" ShowsNavigationUI="False"
Title="Page1">
<Border x:Name="LayoutRoot" Background="White" BorderBrush="#FF646464"
BorderThickness="2" CornerRadius="10" Margin="10">
<Border.Resources>
<ObjectDataProvider x:Key="dataSource" ObjectType="{x:Type local:Members}" MethodName="GetMales" />
</Border.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Center" TextWrapping="Wrap"
Text="WPF ObjectDataProvider 範例" VerticalAlignment="Center" FontSize="26.667"
FontWeight="Bold" Foreground="#FF646464" />
<Rectangle Fill="#FF646464" Height="2" Margin="10,0" VerticalAlignment="Bottom" />
<DataGrid x:Name="grdSample" Grid.Row="1" Margin="10" IsReadOnly="True" AutoGenerateColumns="True"
ItemsSource="{Binding Source={StaticResource dataSource}}" FontSize="14.667"/>
<StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="0,0,0,10">
<TextBlock TextWrapping="Wrap" Text="ObjectType:" VerticalAlignment="Center" FontSize="14.667"
Foreground="#FF646464" FontWeight="Bold"/>
<ComboBox x:Name="cmbType" VerticalAlignment="Center" SelectedIndex="0" Width="150"
SelectionChanged="cmbType_SelectionChanged">
<ComboBoxItem Content="Members"/>
<ComboBoxItem Content="Products"/>
</ComboBox>
<TextBlock TextWrapping="Wrap" Text="MethodName:" VerticalAlignment="Center" FontSize="14.667"
Foreground="#FF646464" Margin="20,0,0,0" FontWeight="Bold"/>
<ComboBox x:Name="cmbMembers" VerticalAlignment="Center" SelectedIndex="0" Width="150">
<ComboBoxItem Content="GetMales"/>
<ComboBoxItem Content="GetFemales"/>
</ComboBox>
<ComboBox x:Name="cmbProducts" VerticalAlignment="Center" SelectedIndex="0" Width="150" Visibility="Collapsed">
<ComboBoxItem Content="GetWindowPhones"/>
<ComboBoxItem Content="GetAndroidPhones"/>
</ComboBox>
<Button x:Name="btnUpdateDataSource" Content="更新資料源" FontSize="13.333" Padding="10,1" Margin="10,0,0,0"
Click="btnUpdateDataSource_Click" />
</StackPanel>
</Grid>
</Border>
</Page>
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 Wpf_ObjectDataProvider
{
public partial class Page1 : Page
{
private ObjectDataProvider _objectDataProvider;
public Page1()
{
InitializeComponent();
_objectDataProvider = this.LayoutRoot.FindResource( "dataSource" ) as ObjectDataProvider;
}
private void cmbType_SelectionChanged( object sender , SelectionChangedEventArgs e )
{
if( this.cmbMembers == null || this.cmbProducts == null )
{
return;
}
this.cmbMembers.Visibility = System.Windows.Visibility.Collapsed;
this.cmbProducts.Visibility = System.Windows.Visibility.Collapsed;
switch( (cmbType.SelectedItem as ComboBoxItem).Content.ToString() )
{
case "Members":
this.cmbMembers.Visibility = System.Windows.Visibility.Visible;
break;
case "Products":
this.cmbProducts.Visibility = System.Windows.Visibility.Visible;
break;
}
}
private void btnUpdateDataSource_Click( object sender , RoutedEventArgs e )
{
switch( ( cmbType.SelectedItem as ComboBoxItem ).Content.ToString() )
{
case "Members":
_objectDataProvider.ObjectType = typeof( Members );
_objectDataProvider.MethodName = ( cmbMembers.SelectedValue as ComboBoxItem ).Content.ToString();
break;
case "Products":
_objectDataProvider.ObjectType = typeof( Products );
_objectDataProvider.MethodName = ( cmbProducts.SelectedValue as ComboBoxItem ).Content.ToString();
break;
}
this._objectDataProvider.Refresh() ;
if( _objectDataProvider.Error != null )
{
MessageBox.Show( _objectDataProvider.Error.Message );
}
}
}
}
就這麼簡單,一點都不難吧!!而在使用ObjectDataProvider的時候,如果像上面的範例一樣,會有兩種不同的資料來源類別,而用來呈現資料的元件又不是DataGrid的話,就得配合相對應的DataTemplate,才能呈現不同類別的資料喔!!(當然也可以再把上面的範例改成透過MethodPrameters來做得更漂亮喔~不過這個就留給大家自己練習啦!!)
最後,一樣奉上專案原始碼,請自行服用: