Silverlight自定义模板控件中不能绑定到目标数据源的问题?-小心DataContext陷阱

   在Silverlight的世界里,数据绑定无疑是一个非常迷人的功能,通过这个功能我们可以使用XAML标记或CLR代码来连接到特定的数据源,内部SIilverligth核心帮助我们完成数据类型之间的转换,例如我们如果有一组ImageSource源,那么我们通过视觉元素Image的Source=“{Binding }”可以直接得到显示的图片。

   不过笔者在最近的一个设计中使用了一个Silverlight自定义的ToggleButton模块控件,在按照通常的方式添加了相应的模板部件和依赖属性后,能绑定到某些属性,而另一个依赖属性并没有按照我的预想的进行工作,通过再三的反复的实验,才发现是掉入了DataContext陷阱中。

   现在我们来具体看一下我们的我们自定义的模板控件,其实这个模板控件很简单,在启动Visual Studio 2010后,新建一个Silverlight项目,然后在添加新项中选择SIilverlight模板控件,如图所示:

  捕获

  这样我们就添加了一个自定义的目标控件,在这儿VS自动为我们的项目添加了一个*.cs的代码文件和一个*.xaml的字典文件,在.cs文件中我们可以定义自已的逻辑,而在字典文件中定义控件的样式集。

   目的:我们要在模板控件中绑定两个属性,这两个属性是为了暴露给外部的使用都而设计的。为了利用自动更新的机制我们定义这两个属性为依赖属性。这两个依赖属性也充当了两个功能,一个是将绑定到外部的数据源,还有一个功能就是绑定到样式的元素属性。

   1、定义两个依赖属性:一个ImageSource和一个bool.这两个依赖属性的定义如下,稍后我们会用到它们。 

代码
public static readonly DependencyProperty CardPhotoProperty;
public static readonly DependencyProperty IsBackProperty;
static CardToggleButton()
{
CardPhotoProperty
= DependencyProperty.Register("CardPhotoSource", typeof(ImageSource), typeof(CardToggleButton), new PropertyMetadata(null, OnPhotoChanged));
IsBackProperty
= DependencyProperty.Register("IsBack", typeof(Visibility), typeof(CardToggleButton), new PropertyMetadata(Visibility.Collapsed,OnBackChanged));
}


//是?否?显?示?背?景°
public Visibility IsBack
{
get { return (Visibility)GetValue(IsBackProperty); }
set { SetValue(IsBackProperty, value); }
}

//前°景°图?
public ImageSource CardPhotoSource
{
get { return (ImageSource)GetValue(CardPhotoProperty); }
set { SetValue(CardPhotoProperty, value); }
}

 


       2、为了在样式模板中绑定这两个属性,我们还要这两个依赖属性设置到上下文,这就是DataContext了,在代码的构造器中加入以下的代码:

 

捕获

 

      3、现在设置样式模板的绑定:同样中这儿我们使用了绑定上下文,将这两个依赖属性分别绑定到Image的Source属性上和Visibility上。样式代码如下:

      Code

 

        4、现在做一些其他的诸如在*.cs文件中定义模板部件和其他的逻辑,为了使用这个部件,需要定义一个重写OnApplyTemplate()虚方法,相应的代码如下:

代码
public override void OnApplyTemplate()
{ base.OnApplyTemplate();
LayoutRoot = GetTemplateChild("layoutRoot") as Grid;
if (IsBack==Visibility.Collapsed)
{ LayoutRoot.MouseEnter += (o, e) =>
{ VisualStateManager.GoToState(this, "MouseEnter", true);
}; LayoutRoot.MouseLeave += (o, e) =>
{ VisualStateManager.GoToState(this, "MouseLeave", true); };
LayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(CardToggleButton_MouseLeftButtonDown); }
else LayoutRoot.MouseLeftButtonDown -= new MouseButtonEventHandler(CardToggleButton_MouseLeftButtonDown); }

 类型定义:

    [TemplatePart(Name = "layoutRoot", Type = typeof(Grid))]
    [TemplatePart(Name="image",Type=typeof (Image ))]
    public class CardToggleButton : ToggleButton

 

5、在外部使用这个模板控件,并使用绑定。

     
   通过实验发现这个CardPhotoSource并不能按预想的那样绑定到了源的ImageSource上,只是一个NULL值的绑定【实际上它是绑定到了CardToggleButton类的自己的CardPhoto依赖属性,亦即绑定到了自身】,所以不能图像并没有显示出来。

    经过分析Silverlight对DataContext绑定采用的是就近原则,而模板设计中我们在构造器中把自身添加到了绑定上下文中,所以在CardPhotoSource绑定到了自身,故不能得到源的属性。

  

    所以这儿的绑定只是绑定的上下文是自身的DataContext,而不是父元素的DataContext中。所以为了使用绑定上下文对象,我们必须改变绑定上下文,让他们各自绑定到自己合适的上下文中,即是如下所示:

     1、 模板控件中的构造器:去除DataContext=this;即构造器如下:

        public CardToggleButton()
        {
            this.DefaultStyleKey = typeof(CardToggleButton);
        }

     2、在模板控件的定义中的进行降级调用:

    

   经过这样的改动,现在所有的绑定都能进行正常的绑定了。笔者在几大的搜索中都没有找到相关的解决方法,所以在此贴出来给开发中遇到此类问题的同业者们一个提示,免得再走冤路。总之使用DataContext要注意,一定要记住“就近原则”。


   完整的模板定义:

 

  

CardToggleButton.cs
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:FightsLandlordApp_ViewModel="clr-namespace:FightsLandlordApp.ViewModel" xmlns:local="clr-namespace:FightsLandlordApp" xmlns:control="clr-namespace:FightsLandlordApp.Controls"
xmlns:card
="clr-namespace:FightsLandlordApp.Models" xmlns:converter="clr-namespace:FightsLandlordApp.Converters"
xmlns:SampleData
="clr-namespace:Expression.Blend.SampleData.SampleDataSource"
xmlns:i
="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
mc:Ignorable
="d"
x:Class
="FightsLandlordApp.App"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>

<converter:ImageSourceToImageSource x:Key="imageSourceConverter"/>
<FightsLandlordApp_ViewModel:CardViewModel x:Key="CardViewModelDataSource" d:IsDataSource="True">
<FightsLandlordApp_ViewModel:CardViewModel.TotalCards>
<card:Card CardNo="1" CardRank="Rank3" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades3.png"/>
<card:Card CardNo="2" CardRank="Rank4" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades4.png"/>
<card:Card CardNo="3" CardRank="Rank5" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades5.png"/>
<card:Card CardNo="4" CardRank="Rank6" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades6.png"/>
<card:Card CardNo="5" CardRank="Rank7" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades7.png"/>
<card:Card CardNo="6" CardRank="Rank8" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades8.png"/>
<card:Card CardNo="7" CardRank="Rank9" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades9.png"/>
<card:Card CardNo="8" CardRank="Rank10" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades10.png"/>
<card:Card CardNo="9" CardRank="RankJ" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spadesJ.png"/>
<card:Card CardNo="10" CardRank="RankQ" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spadesQ.png"/>
<card:Card CardNo="11" CardRank="RankK" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spadesK.png"/>
<card:Card CardNo="12" CardRank="RankA" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spadesA.png"/>
<card:Card CardNo="13" CardRank="Rank2" CardSuit="Spades" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/spades2.png"/>

<card:Card CardNo="14" CardRank="Rank3" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts3.png"/>
<card:Card CardNo="15" CardRank="Rank4" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts4.png"/>
<card:Card CardNo="16" CardRank="Rank5" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts5.png"/>
<card:Card CardNo="17" CardRank="Rank6" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts6.png"/>
<card:Card CardNo="18" CardRank="Rank7" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts7.png"/>
<card:Card CardNo="19" CardRank="Rank8" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts8.png"/>
<card:Card CardNo="20" CardRank="Rank9" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts9.png"/>
<card:Card CardNo="21" CardRank="Rank10" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts10.png"/>
<card:Card CardNo="22" CardRank="RankJ" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/HeartsJ.png"/>
<card:Card CardNo="23" CardRank="RankQ" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/HeartsQ.png"/>
<card:Card CardNo="24" CardRank="RankK" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/HeartsK.png"/>
<card:Card CardNo="25" CardRank="RankA" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/HeartsA.png"/>
<card:Card CardNo="26" CardRank="Rank2" CardSuit="Hearts" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Hearts2.png"/>

<card:Card CardNo="27" CardRank="Rank3" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds3.png"/>
<card:Card CardNo="28" CardRank="Rank4" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds4.png"/>
<card:Card CardNo="29" CardRank="Rank5" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds5.png"/>
<card:Card CardNo="30" CardRank="Rank6" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds6.png"/>
<card:Card CardNo="31" CardRank="Rank7" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds7.png"/>
<card:Card CardNo="32" CardRank="Rank8" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds8.png"/>
<card:Card CardNo="33" CardRank="Rank9" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds9.png"/>
<card:Card CardNo="34" CardRank="Rank10" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds10.png"/>
<card:Card CardNo="35" CardRank="RankJ" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/DiamondsJ.png"/>
<card:Card CardNo="36" CardRank="RankQ" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/DiamondsQ.png"/>
<card:Card CardNo="37" CardRank="RankK" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/DiamondsK.png"/>
<card:Card CardNo="38" CardRank="RankA" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/DiamondsA.png"/>
<card:Card CardNo="39" CardRank="Rank2" CardSuit="Diamonds" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Diamonds2.png"/>

<card:Card CardNo="40" CardRank="Rank3" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs3.png"/>
<card:Card CardNo="41" CardRank="Rank4" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs4.png"/>
<card:Card CardNo="42" CardRank="Rank5" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs5.png"/>
<card:Card CardNo="43" CardRank="Rank6" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs6.png"/>
<card:Card CardNo="44" CardRank="Rank7" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs7.png"/>
<card:Card CardNo="45" CardRank="Rank8" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs8.png"/>
<card:Card CardNo="46" CardRank="Rank9" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs9.png"/>
<card:Card CardNo="47" CardRank="Rank10" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs10.png"/>
<card:Card CardNo="48" CardRank="RankJ" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/ClubsJ.png"/>
<card:Card CardNo="49" CardRank="RankQ" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/ClubsQ.png"/>
<card:Card CardNo="50" CardRank="RankK" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/ClubsK.png"/>
<card:Card CardNo="51" CardRank="RankA" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/ClubsA.png"/>
<card:Card CardNo="52" CardRank="Rank2" CardSuit="Clubs" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/Clubs2.png"/>

<card:Card CardNo="53" CardRank="RankB" CardSuit="Other" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/JokerB.png"/>
<card:Card CardNo="54" CardRank="RankR" CardSuit="Other" CardState="All" CardPhoto="/FightsLandlordApp;Component/Images/JokerR.png"/>
</FightsLandlordApp_ViewModel:CardViewModel.TotalCards>
</FightsLandlordApp_ViewModel:CardViewModel>

<SampleData:SampleDataSource x:Key="SampleDataSource" d:IsDataSource="True"/>

<LinearGradientBrush x:Key="StrokeBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#B2FFFFFF" Offset="0.657"/>
<GradientStop Color="#666179D8" Offset="1"/>
<GradientStop Color="#7E93A4E4"/>
<GradientStop Color="#8DB3BFEC" Offset="0.459"/>
<GradientStop Color="#A9ECEFFA" Offset="0.189"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="cardBackBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF5F65C4" Offset="0"/>
<GradientStop Color="#66FFFFFF" Offset="0.481"/>
<GradientStop Color="#F5686EC7" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="TransparentBackStyle" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#72FFFFFF" Offset="0"/>
<GradientStop Color="#19FFFFFF" Offset="0.485"/>
<GradientStop Color="#72FFFFFF" Offset="1"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="backBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF8EE493" Offset="0"/>
<GradientStop Color="#FF95E59A" Offset="1"/>
<GradientStop Color="#FFC1EFC4" Offset="0.485"/>
</LinearGradientBrush>

<Style x:Key="TextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="26.667"/>
<Setter Property="FontFamily" Value="Arial Black"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="Margin" Value="0,0,0,5"/>
</Style>
<LinearGradientBrush x:Key="CardNormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#00FFFFFF" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="0.5" />
<GradientStop Color="#33AAAAAA" Offset="1" />
</LinearGradientBrush>


<Style x:Key="PlayerInfoStyle" TargetType="ToggleButton">
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">

<Storyboard>
<DoubleAnimation Duration="0" To="5" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" Storyboard.TargetName="Background" d:IsOptimized="True"/>
</Storyboard>

</VisualState>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled">

<Storyboard>
<ColorAnimation Duration="0" To="#72000000" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#72000000" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(TextBlock.Text)" Storyboard.TargetName="message">
<DiscreteObjectKeyFrame KeyTime="0" Value="没有玩家"/>
</ObjectAnimationUsingKeyFrames>
<ColorAnimation Duration="0" To="White" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="message" d:IsOptimized="True"/>
</Storyboard>

</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">

<Storyboard>
<ColorAnimation Duration="0" To="#724172C2" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#725B8AD6" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#19698FCC" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(TextBlock.Text)" Storyboard.TargetName="message">
<DiscreteObjectKeyFrame KeyTime="0" Value="已经加入"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="已经加入"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="message">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

</VisualState>
<VisualState x:Name="Unchecked"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Background">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" Opacity="0.6" />
</Border.Effect>
<Rectangle x:Name="rectangle" StrokeThickness="2" RadiusY="5" RadiusX="5" Stroke="{StaticResource StrokeBrush}" >
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#72FFFFFF" Offset="0"/>
<GradientStop Color="#19FFFFFF" Offset="0.485"/>
<GradientStop Color="#72FFFFFF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Border>
<ContentPresenter />
<TextBlock x:Name="message" Text="点击加入游戏" Foreground="#FF211AF3" FontSize="16" VerticalAlignment="Bottom" Margin="0,0,0,30" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsPanelTemplate x:Key="ItemsPanelStyle">
<local:CardsPanel IsHorizontal="True">
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children" Tag="DataContext" Duration="0:0:0.3">
<ei:FluidMoveBehavior.EaseY>
<CircleEase EasingMode="EaseOut"/>
</ei:FluidMoveBehavior.EaseY>
<ei:FluidMoveBehavior.EaseX>
<CircleEase EasingMode="EaseIn"/>
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
</local:CardsPanel>
</ItemsPanelTemplate>

<ItemsPanelTemplate x:Key="ItemsVerticalPanelStyle">
<local:CardsPanel >
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children" Duration="0:0:0.3" Tag="DataContext">
<ei:FluidMoveBehavior.EaseY>
<CircleEase EasingMode="EaseOut"/>
</ei:FluidMoveBehavior.EaseY>
<ei:FluidMoveBehavior.EaseX>
<CircleEase EasingMode="EaseIn"/>
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
</local:CardsPanel>
</ItemsPanelTemplate>

<ItemsPanelTemplate x:Key="TotalItemsPanelStyle">
<local:TotalViewPanel>
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children" Duration="0:0:0.3" Tag="DataContext">
<ei:FluidMoveBehavior.EaseY>
<CircleEase EasingMode="EaseOut"/>
</ei:FluidMoveBehavior.EaseY>
<ei:FluidMoveBehavior.EaseX>
<CircleEase EasingMode="EaseIn"/>
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
</local:TotalViewPanel>
</ItemsPanelTemplate>

<Style x:Key="ToggleButtonStyle1" TargetType="ToggleButton">
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="layoutRoot">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<DataTemplate x:Key="CardToggleButtonStyle">
<Grid>
<control:CardToggleButton IsBack="Collapsed" CardPhotoSource="{Binding CardPhoto}"/>
</Grid>
</DataTemplate>

<DataTemplate x:Key="CardToggleButtonVerticalStyle">
<Grid>
<control:CardToggleButton IsBack="Visible" CardPhotoSource="{Binding CardPhoto}"/>
</Grid>
</DataTemplate>

<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Padding" Value="10 25 0 0"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>

</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="TotalListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundAnimation"/>
<ColorAnimation Duration="0" To="#F2FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#CCFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#7FFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0" To="#FF6DBDD1" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Background"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundAnimation"/>
<ColorAnimation Duration="0" To="#D8FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#C6FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#8CFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
<ColorAnimation Duration="0" To="#3FFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualElement"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Background" BorderThickness="{TemplateBinding BorderThickness}" Background="#FFF5A94D" CornerRadius="3">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#4CFFFFFF" Offset="0"/>
<GradientStop Color="#99FFFFFF" Offset="0.375"/>
<GradientStop Color="#99FFFFFF" Offset="0.376"/>
<GradientStop Color="#19FFFFFF" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Grid Margin="0">
<Grid.Background>

<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFE48686" Offset="0"/>
<GradientStop Color="#FFF15656" Offset="1"/>
<GradientStop Color="#B2F13A3A" Offset="0.474"/>
</LinearGradientBrush>

</Grid.Background>
<Border x:Name="BackgroundAnimation" Background="{StaticResource backBrush}" Opacity="0"/>
<Rectangle x:Name="BackgroundGradient">
<Rectangle.Fill>
<LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
<GradientStop Color="#99FFFFFF" Offset="0"/>
<GradientStop Color="#33FFFFFF" Offset="0.375"/>
<GradientStop Color="#99FFFFFF" Offset="0.625"/>
<GradientStop Color="#33FFFFFF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Rectangle x:Name="DisabledVisualElement" Fill="#FFFFFFFF" IsHitTestVisible="false" Opacity="0" RadiusY="3" RadiusX="3"/>
<Rectangle x:Name="FocusVisualElement" IsHitTestVisible="false" Margin="1" Opacity="0" RadiusY="2" RadiusX="2" Stroke="#FF6DBDD1" StrokeThickness="1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

 

Gereric.xaml
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;

namespace FightsLandlordApp.Controls
{
[TemplatePart(Name
= "layoutRoot", Type = typeof(Grid))]
[TemplatePart(Name
="image",Type=typeof (Image ))]
public class CardToggleButton : ToggleButton
{

private Grid LayoutRoot;
private Image image;

public static readonly DependencyProperty CardPhotoProperty;
public static readonly DependencyProperty IsBackProperty;
static CardToggleButton()
{
CardPhotoProperty
= DependencyProperty.Register("CardPhotoSource", typeof(ImageSource), typeof(CardToggleButton), new PropertyMetadata(null, OnPhotoChanged));
IsBackProperty
= DependencyProperty.Register("IsBack", typeof(Visibility), typeof(CardToggleButton), new PropertyMetadata(Visibility.Collapsed,OnBackChanged));
}
private static void OnPhotoChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
((CardToggleButton)sender).RefreshPhoto();
}
private static void OnBackChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
((CardToggleButton)sender).RefreshPhoto();
}

private void RefreshPhoto()
{
}
private bool isSwitch = false;
void CardToggleButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isSwitch
= !isSwitch;
if (isSwitch)
{
this.RenderTransform = new CompositeTransform { TranslateY = -20 };//移动
}
else
this.RenderTransform = new CompositeTransform { TranslateY = 0 };
}
//是否显示背景
public Visibility IsBack
{
get { return (Visibility)GetValue(IsBackProperty); }
set { SetValue(IsBackProperty, value); }
}

//前景图
public ImageSource CardPhotoSource
{
get { return (ImageSource)GetValue(CardPhotoProperty); }
set { SetValue(CardPhotoProperty, value); }
}


public CardToggleButton()
{
this.DefaultStyleKey = typeof(CardToggleButton);
}


public override void OnApplyTemplate()
{
base.OnApplyTemplate();
LayoutRoot
= GetTemplateChild("layoutRoot") as Grid;
LayoutRoot.DataContext
= this;

if (IsBack==Visibility.Collapsed)
{
LayoutRoot.MouseEnter
+= (o, e) =>
{
VisualStateManager.GoToState(
this, "MouseEnter", true);
};
LayoutRoot.MouseLeave
+= (o, e) =>
{
VisualStateManager.GoToState(
this, "MouseLeave", true);
};

LayoutRoot.MouseLeftButtonDown
+= new MouseButtonEventHandler(CardToggleButton_MouseLeftButtonDown);
}
else
LayoutRoot.MouseLeftButtonDown
-= new MouseButtonEventHandler(CardToggleButton_MouseLeftButtonDown);
}
}
}

 

 

 

posted @ 2010-07-27 20:42  suyan010203  Views(2939)  Comments(2Edit  收藏