在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); }
5、在外部使用这个模板控件,并使用绑定。
通过实验发现这个CardPhotoSource并不能按预想的那样绑定到了源的ImageSource上,只是一个NULL值的绑定【实际上它是绑定到了CardToggleButton类的自己的CardPhoto依赖属性,亦即绑定到了自身】,所以不能图像并没有显示出来。
经过分析Silverlight对DataContext绑定采用的是就近原则,而模板设计中我们在构造器中把自身添加到了绑定上下文中,所以在CardPhotoSource绑定到了自身,故不能得到源的属性。
所以这儿的绑定只是绑定的上下文是自身的DataContext,而不是父元素的DataContext中。所以为了使用绑定上下文对象,我们必须改变绑定上下文,让他们各自绑定到自己合适的上下文中,即是如下所示:
1、 模板控件中的构造器:去除DataContext=this;即构造器如下:
public CardToggleButton()
{
this.DefaultStyleKey = typeof(CardToggleButton);
}
2、在模板控件的定义中的进行降级调用:
经过这样的改动,现在所有的绑定都能进行正常的绑定了。笔者在几大的搜索中都没有找到相关的解决方法,所以在此贴出来给开发中遇到此类问题的同业者们一个提示,免得再走冤路。总之使用DataContext要注意,一定要记住“就近原则”。
完整的模板定义:
< 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 >
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);
}
}
}