在WPF内可以使用DataTemplate,来辅助完成对对象集合做DataBinding的工作。并且透过DataTemplate的DataType属性,来让对象集合中不同的对象,经过DataBinding之后能有「不同的外观」。简单的范例如下:不同的车辆类型,会依照车辆类型,呈现不同的详细数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
namespace
BindingInterfaceSample
{
public
class
Car
{
public
string
Name {
get
;
set
; }
}
public
class
Truck : Car
{
public
int
MaxLoad {
get
;
set
; }
}
public
class
Roadster : Car
{
public
int
MaxSpeed {
get
;
set
; }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<
Window
x:Class
=
"BindingInterfaceSample.MainWindow"
xmlns:clk
=
"clr-namespace:BindingInterfaceSample"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
ItemsControl
>
<
ItemsControl.Items
>
<
clk:Truck
Name
=
"Truck01"
MaxLoad
=
"100"
/>
<
clk:Truck
Name
=
"Truck02"
MaxLoad
=
"500"
/>
<
clk:Roadster
Name
=
"Roadster01"
MaxSpeed
=
"99"
/>
</
ItemsControl.Items
>
<
ItemsControl.Resources
>
<
DataTemplate
DataType
=
"{x:Type clk:Truck}"
>
<
WrapPanel
>
<
TextBlock
Text
=
"Truck"
/>
<
TextBlock
Text
=
"{Binding Path=MaxLoad}"
/>
</
WrapPanel
>
</
DataTemplate
>
<
DataTemplate
DataType
=
"{x:Type clk:Roadster}"
>
<
WrapPanel
>
<
TextBlock
Text
=
"Roadster"
/>
<
TextBlock
Text
=
"{Binding Path=MaxSpeed}"
/>
</
WrapPanel
>
</
DataTemplate
>
</
ItemsControl.Resources
>
</
ItemsControl
>
</
Window
>
|
反过来说,也可以经由DataTemplate的DataType属性,来让对象集合中不同的对象,经过DataBinding之后能有「相同的外观」。简单的范例如下:只要是车,都只呈现车的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
namespace
BindingInterfaceSample
{
public
class
Car
{
public
string
Name {
get
;
set
; }
}
public
class
Truck : Car
{
public
int
MaxLoad {
get
;
set
; }
}
public
class
Roadster : Car
{
public
int
MaxSpeed {
get
;
set
; }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<
Window
x:Class
=
"BindingInterfaceSample.MainWindow"
xmlns:clk
=
"clr-namespace:BindingInterfaceSample"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
ItemsControl
>
<
ItemsControl.Items
>
<
clk:Truck
Name
=
"Truck01"
MaxLoad
=
"100"
/>
<
clk:Truck
Name
=
"Truck02"
MaxLoad
=
"500"
/>
<
clk:Roadster
Name
=
"Roadster01"
MaxSpeed
=
"99"
/>
</
ItemsControl.Items
>
<
ItemsControl.Resources
>
<
DataTemplate
DataType
=
"{x:Type clk:Car}"
>
<
Button
Content
=
"{Binding Path=Name}"
/>
</
DataTemplate
>
</
ItemsControl.Resources
>
</
ItemsControl
>
</
Window
>
|
而在让对象集合中不同的对象,经过DataBinding之后能有「相同的外观」。这个使用情景中,DataTemplate的DataType如果设定为Interface型别,在WPF中会出现意外的执行结果。简单的范例如下:DataType设定为Interface型别,会无法对应DataTemplate。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
namespace
BindingInterfaceSample
{
public
interface
ICar
{
string
Name {
get
;
set
; }
}
public
class
Truck : ICar
{
public
string
Name {
get
;
set
; }
public
int
MaxLoad {
get
;
set
; }
}
public
class
Roadster : ICar
{
public
string
Name {
get
;
set
; }
public
int
MaxSpeed {
get
;
set
; }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<
Window
x:Class
=
"BindingInterfaceSample.MainWindow"
xmlns:clk
=
"clr-namespace:BindingInterfaceSample"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
ItemsControl
>
<
ItemsControl.Items
>
<
clk:Truck
Name
=
"Truck01"
MaxLoad
=
"100"
/>
<
clk:Truck
Name
=
"Truck02"
MaxLoad
=
"500"
/>
<
clk:Roadster
Name
=
"Roadster01"
MaxSpeed
=
"99"
/>
</
ItemsControl.Items
>
<
ItemsControl.Resources
>
<
DataTemplate
DataType
=
"{x:Type clk:ICar}"
>
<
Button
Content
=
"{Binding Path=Name}"
/>
</
DataTemplate
>
</
ItemsControl.Resources
>
</
ItemsControl
>
</
Window
>
|
遇到必须设定DataTemplate的DataType为Interface型别的情景。解决的方法很简单:只要改写数据系结容器使用的DataTemplateSelector,增加以Interface型别做索引,查询Resource里的DataTemplate,再用这个DataTemplate来做DataBinding。简单的范例如下:只要是有实做车接口,都只呈现车的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
namespace
BindingInterfaceSample
{
public
interface
ICar
{
string
Name {
get
;
set
; }
}
public
class
Truck : ICar
{
public
string
Name {
get
;
set
; }
public
int
MaxLoad {
get
;
set
; }
}
public
class
Roadster : ICar
{
public
string
Name {
get
;
set
; }
public
int
MaxSpeed {
get
;
set
; }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<
Window
x:Class
=
"BindingInterfaceSample.MainWindow"
xmlns:clk
=
"clr-namespace:BindingInterfaceSample"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
ItemsControl
>
<
ItemsControl.Items
>
<
clk:Truck
Name
=
"Truck01"
MaxLoad
=
"100"
/>
<
clk:Truck
Name
=
"Truck02"
MaxLoad
=
"500"
/>
<
clk:Roadster
Name
=
"Roadster01"
MaxSpeed
=
"99"
/>
</
ItemsControl.Items
>
<
ItemsControl.Resources
>
<
DataTemplate
DataType
=
"{x:Type clk:ICar}"
>
<
Button
Content
=
"{Binding Path=Name}"
/>
</
DataTemplate
>
</
ItemsControl.Resources
>
<
ItemsControl.ItemTemplateSelector
>
<
clk:StandardDataTemplateSelector
/>
</
ItemsControl.ItemTemplateSelector
>
</
ItemsControl
>
</
Window
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
namespace
BindingInterfaceSample
{
public
class
StandardDataTemplateSelector : DataTemplateSelector
{
// Methods
public
override
DataTemplate SelectTemplate(
object
item, DependencyObject container)
{
#region Require
if
(item ==
null
)
throw
new
ArgumentNullException();
if
(container ==
null
)
throw
new
ArgumentNullException();
#endregion
// Result
DataTemplate itemDataTemplate =
null
;
// Base DataTemplate
itemDataTemplate =
base
.SelectTemplate(item, container);
if
(itemDataTemplate !=
null
)
return
itemDataTemplate;
// Interface DataTemplate
FrameworkElement itemContainer = container
as
FrameworkElement;
if
(itemContainer ==
null
)
return
null
;
foreach
(Type itemInterface
in
item.GetType().GetInterfaces())
{
itemDataTemplate = itemContainer.TryFindResource(
new
DataTemplateKey(itemInterface))
as
DataTemplate;
if
(itemDataTemplate !=
null
)
break
;
}
// Return
return
itemDataTemplate;
}
}
}
|