WP7自定义控件 评分控件

最近在写一个新的APP程序,需要使用评分功能,WP的Toolkit里面没有包含,只能自己写一个了。

 

评分控件要点

评分控件已经很熟悉了,还是总结一下要点。

  1. 由10个(可配置)横排的五星组成,默认非高亮色(灰色)
  2. 得分由从左到右高亮(如红色,颜色可配置)显示得分数量的五星,控件能够提供获取和设置得分的属性。
  3. 可以点击其中一个五星修改评分。
  4. 为了提高触摸体验,支持拖动控件修改得分

 

根据要点设计控件

根据要点1设计控件布局

Horizontal排列的StackPanel(包含在ItemsControl 控件内部) 和 绘制五星的Path 组成。

最上面提供一个透明的Rectangle扩展触摸空间(WP只能在绘制的控件上触摸)。

<ItemsControl x:Name="stars"> 
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="M16,0 L19.77688,12.223213 L32.000001,12.222913 L22.111121,19.776973 L25.888544,32.000001 L16,24.445454 L6.1114563,32.000001 L9.88888,19.776973 L2.2971745E-08,12.222913 L12.22312,12.223213 z"
Fill
="{Binding Fill}" HorizontalAlignment="Left" Height="32" Margin="1,0" Width="32"
Stretch
="Fill" VerticalAlignment="Top" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Rectangle Fill="#00000000"/>



根据要点1、2设计控件属性

Brush MarkedFill  选中了的五星刷子

Brush UnMarkedFill 未选中的五星刷子

int MaxStars 最大五星数量

Marked 当前评价值

 

根据要点2设计控件属性改变行为

很简单获取Marked 然后将每个五星都修改一下颜色

private void FillStars(int index) 
{
if (!VerifyValue(index)) return;

for (int i = 0, length = starItems.Count; i < length; i++)
{
var star = starItems[i];
if (i > index)
{
star.Fill = UnMarkedFill;
}
else
{
star.Fill = MarkedFill;
}
}

}



根据要点3、4设计控件触控行为

将2个要点合并了,实现方法为:

  • 滑动前(点中): 修改为当前X轴的高亮位置
  • 滑动中:根据X轴变化高亮位置
  • 滑动完成(放开): 修改为当前X轴的高亮位置,并更新评分Marked 当前评价值

通过五星的宽度可以获取X轴所在的五星

代码如下:

protected override void OnManipulationStarted(ManipulationStartedEventArgs e) 
{
e.Handled = true;
UpdateStar(e.ManipulationOrigin);
base.OnManipulationStarted(e);
}

protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
{
e.Handled = true;
UpdateStar(e.ManipulationOrigin);
base.OnManipulationDelta(e);
}

protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
e.Handled = true;
var index = UpdateStar(e.ManipulationOrigin);
if (VerifyValue(index)) { Marked = index + 1; }
base.OnManipulationCompleted(e);
}

 

完整代码

 

View Code
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace KimiStudio.Controls
{
public class StarMark : Control
{
private ItemsControl stars;
private const int StarSize = 34;
private ObservableCollection<StarItem> starItems;

#region DependencyPropertys
public static readonly DependencyProperty MarkedFillProperty =
DependencyProperty.Register("MarkedFill", typeof(Brush), typeof(StarMark),
new PropertyMetadata(new SolidColorBrush(Colors.Red)));

public static readonly DependencyProperty UnMarkedFillProperty =
DependencyProperty.Register("UnMarkedFill", typeof(Brush), typeof(StarMark),
new PropertyMetadata(new SolidColorBrush(Colors.DarkGray)));

public static readonly DependencyProperty MaxStarsProperty =
DependencyProperty.Register("MaxStars", typeof(int), typeof(StarMark),
new PropertyMetadata(10));

public static readonly DependencyProperty MarkedProperty =
DependencyProperty.Register("Marked", typeof(int), typeof(StarMark),
new PropertyMetadata(0, OnMarkedPropertyChanged));

public int Marked
{
get { return (int)GetValue(MarkedProperty); }
set { SetValue(MarkedProperty, value); }
}

public int MaxStars
{
get { return (int)GetValue(MaxStarsProperty); }
set { SetValue(MaxStarsProperty, value); }
}

public Brush UnMarkedFill
{
get { return (Brush)GetValue(UnMarkedFillProperty); }
set { SetValue(UnMarkedFillProperty, value); }
}

public Brush MarkedFill
{
get { return (Brush)GetValue(MarkedFillProperty); }
set { SetValue(MarkedFillProperty, value); }
}

private static void OnMarkedPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
var starMark = o as StarMark;
if (starMark == null || args.NewValue == args.OldValue) return;

starMark.SetMarked((int)args.NewValue);
}

#endregion

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

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
stars = (ItemsControl)GetTemplateChild("stars");


starItems = new ObservableCollection<StarItem>();
for (int i = 0, length = MaxStars; i < length; i++)
{
starItems.Add(new StarItem { Fill = UnMarkedFill });
}
stars.ItemsSource = starItems;
SetMarked(Marked);
}

private void SetMarked(int value)
{
if (stars == null) return; ;
FillStars(value - 1);
}

protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
{
e.Handled = true;
UpdateStar(e.ManipulationOrigin);
base.OnManipulationStarted(e);
}

protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
{
e.Handled = true;
UpdateStar(e.ManipulationOrigin);
base.OnManipulationDelta(e);
}

protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
e.Handled = true;
var index = UpdateStar(e.ManipulationOrigin);
if (VerifyValue(index)) { Marked = index + 1; }
base.OnManipulationCompleted(e);
}

private int UpdateStar(Point point)
{
int x = (int)point.X;
int index = x / StarSize;
FillStars(index);
return index;
}

//SL可用
//protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
//{
// int x = (int)e.GetPosition(stars).X;
// int index = x / StarSize;
// FillStars(index);

// if (VerifyValue(index)) { Marked = index + 1; }
// base.OnMouseLeftButtonUp(e);
//}


private bool VerifyValue(int index)
{
if (index < 0 || index >= stars.Items.Count) return false;
return true;
}


private void FillStars(int index)
{
if (!VerifyValue(index)) return;

for (int i = 0, length = starItems.Count; i < length; i++)
{
var star = starItems[i];
if (i > index)
{
star.Fill = UnMarkedFill;
}
else
{
star.Fill = MarkedFill;
}
}

}




public class StarItem : INotifyPropertyChanged
{
private Brush fill;

public event PropertyChangedEventHandler PropertyChanged;

public Brush Fill
{
get { return fill; }
set
{
if (fill == value) return;
fill = value;
OnPropertyChanged("Fill");
}
}

private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler == null) return;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

对应的Generic.xaml

View Code
 <Style TargetType="local:StarMark">
<Setter Property="Width" Value="340"/>
<Setter Property="Height" Value="35"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:StarMark">
<Grid>
<ItemsControl x:Name="stars">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="M16,0 L19.77688,12.223213 L32.000001,12.222913 L22.111121,19.776973 L25.888544,32.000001 L16,24.445454 L6.1114563,32.000001 L9.88888,19.776973 L2.2971745E-08,12.222913 L12.22312,12.223213 z"
Fill
="{Binding Fill}" HorizontalAlignment="Left" Height="32" Margin="1,0" Width="32"
Stretch
="Fill" VerticalAlignment="Top" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Rectangle Fill="#00000000"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>



 

posted @ 2012-03-11 19:57  kiminozo  阅读(2211)  评论(13编辑  收藏  举报