前言 虽然本人对彩票不感兴趣,仍然有不少人对此情有独钟。他们花大量时间精力去分析彩票的历史记录,企图发现规律,为下一次投注做指导,希望“赢的“”概率增大。不管研究历史记录是否有意义,我用软件实现了对彩票的分析,手工分析彩票几天工作量,现在一秒可以实现。
程序界面
处理原理分析:
程序实际上是对六合彩分析(彩票种类很多,本文只处理一种)。数据格式如下:
2010001 11 13 22 16 21 18
2010002 22 28 16 5 14 26
2010003 5 14 45 48 16 25
每期6个号,任选3个号,如果6个号中包含该3个号,该期算中奖了。
彩票数值范围为1--49,每期都是6选3. 每次投注3个号,所有的投注可能性有18424次,从概率上讲,每次投注中奖的可能性是18424分之1.
软件就是分析选哪三个号中奖概率最大。是根据历史记录统计分析,找出历史记录上哪些号码出现次数多。
彩票历史记录界面
这是ListView控件,显示彩票历史记录。如何显示这样的界面?这种类型的界面非常适用MVVM模式展示。你准备数据和显示模板,剩下的事由ListView来做。
ListView需要绑定的数据定义如下:
1 public class ListViewBindingItem 2 { 3 public string Index { get; set; } //序号 4 public string RecordNO { get; set; } //期数 5 public string[] Digital { get; set; } 6 public RecordItemInFile RecordItem { get; internal set; } 7 8 public int ValueIndexOf(string value) 9 { 10 for (int i = 0; i < Digital.Length; i++) 11 { 12 if (Digital[i] == value) 13 { 14 return i; 15 } 16 } 17 return -1; 18 } 19 20 public string StrDigital 21 { 22 get 23 { 24 return string.Format("{0} {1} {2} {3} {4} {5}", 25 Digital[0], Digital[1], Digital[2], 26 Digital[3], Digital[4], Digital[5]); 27 } 28 } 29 30 }
这个类型的定义与界面密切相关,与asp.net 中的ViewMode概念相似。如果界面只是显示字符串,把数据绑定到ListView就大功告成。但是我们想把彩票中的数字显示在圆形背景中,这时候就需要用到数据模板DataTemplate。数据模板的输入是数据和模板,输出就是你想要的界面。模板就是定义数据怎么显示的。如何处理数据如何显示有很多种方法,我只举其中一种。注:每种显示效果可能都会有多种处理方法,这是WPF的灵活性,也是wpf让人困惑的地方。
ListView XAML定义如下
<ListView MinHeight="260" BorderThickness="1,1,1,1" VirtualizingPanel.IsVirtualizing="True" Grid.Row="0" x:Name="lvAllDigital" > <ListView.View> <GridView > <GridViewColumn Header="序号" Width="90" DisplayMemberBinding="{Binding Path=Index}"></GridViewColumn> <GridViewColumn Header="期数" Width="110" DisplayMemberBinding="{Binding Path=RecordNO}"></GridViewColumn> <GridViewColumn Header="1列" Width="55" CellTemplate="{StaticResource ColDigital1}"></GridViewColumn> <GridViewColumn Header="2列" Width="55" CellTemplate="{StaticResource ColDigital2}"></GridViewColumn> <GridViewColumn Header="3列" Width="55" CellTemplate="{StaticResource ColDigital3}"></GridViewColumn> <GridViewColumn Header="4列" Width="55" CellTemplate="{StaticResource ColDigital4}"></GridViewColumn> <GridViewColumn Header="5列" Width="55" CellTemplate="{StaticResource ColDigital5}"></GridViewColumn> <GridViewColumn Header="6列" Width="55" CellTemplate="{StaticResource ColDigital6}"></GridViewColumn> </GridView> </ListView.View> </ListView>
数字显示的模板定义如下:
<DataTemplate x:Key="ColDigital1" > <StackPanel Margin="5,2,5,2" HorizontalAlignment="Center" Width="180"> <local:CustomControl_digital x:Name="labelDigital1" Width="30" Height="30" StrDigital="{Binding Path=Digital[0]}"></local:CustomControl_digital> </StackPanel> </DataTemplate>
CustomControl_digital类是一个自定义控件,这个控件就是根据输入的数字,显示圆形背景图像。这个处理也很简单。
public class CustomControl_digital : Control { public static readonly DependencyProperty StrDigitalProperty; public static Color defaultColor = Color.FromRgb(41, 57, 85); Color BackColor { get; set; } = defaultColor; static CustomControl_digital() { StrDigitalProperty = DependencyProperty.Register("StrDigital", //属性名称 typeof(string), //属性类型 typeof(CustomControl_digital), //该属性所有者,即将该属性注册到那个类上 new PropertyMetadata("")); //属性默认值 DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl_digital), new FrameworkPropertyMetadata(typeof(CustomControl_digital))); } public void SetBackColor(int index) { if (index == 0) BackColor = defaultColor; else BackColor = Color.FromRgb(62, 175, 14); } public int Row { get; set; } = -1; public int Column { get; set; } public string StrDigital_old { get; set; } public string StrDigital { get { return (string)GetValue(StrDigitalProperty); } set { SetValue(StrDigitalProperty, value); } } static Dictionary<Brush, Pen> _colorToPenGroup = new Dictionary<Brush, Pen>(); public static Pen GetPen(Brush color) { if(_colorToPenGroup.TryGetValue(color,out Pen pen)) { return pen; } Pen pen2 = new Pen(color, 0); pen2.Freeze(); _colorToPenGroup.Add(color, pen2); return pen2; } static Dictionary<Color, SolidColorBrush> _colorToBrushGroup = new Dictionary<Color, SolidColorBrush>(); public static SolidColorBrush GetBrush(Color color) { if (_colorToBrushGroup.TryGetValue(color, out SolidColorBrush brush)) { return brush; } SolidColorBrush newBrush = new SolidColorBrush(color); newBrush.Freeze(); _colorToBrushGroup.Add(color, newBrush); return newBrush; } protected override void OnRender(DrawingContext dc) { base.OnRender(dc); if (StrDigital == "--") return; double len = Math.Min(ActualHeight, ActualWidth); Point center = new Point(ActualWidth / 2, ActualHeight / 2); Pen pen = GetPen(Brushes.Black); Brush brush = GetBrush(BackColor); double totalRadius = len / 2; double radius = totalRadius * 9 / 10; dc.DrawEllipse(brush, pen, center, radius, radius); if (!string.IsNullOrEmpty(StrDigital)) { FormattedText text = new FormattedText(StrDigital, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 14, Brushes.White); Point txtPoint = new Point(center.X - 9, center.Y - 8); dc.DrawText(text, txtPoint); } } }
因为需要绑定数据,所以需要定义依赖属性。需要重载函数 protected override void OnRender(DrawingContext dc),在这个函数中处理显示。
彩票中奖结果界面
这个也是ListView控件,只是数据模板定义不一样。数据模板定义如下:
<DataTemplate x:Key="keyDigitalView" > <StackPanel Margin="5,2,5,2" HorizontalAlignment="Center" Width="180"> <local:UserControl_DigitalView x:Name="digitalView" StrDigital="{Binding Path=StrDigital}" StrHighlight="{Binding Path=StrHighlight}"> </local:UserControl_DigitalView> </StackPanel> </DataTemplate>
要显示这样的效果需要知道两个参数:1 需要显示哪些数字,2 哪些数字需要绿色背景。这两个参数是 StrDigital,StrHighlight。我们生成用户控件,同时定义这两个参数;为了可以绑定,参数必须定义为依赖属性。
UserControl_DigitalView控件定义如下:
public partial class UserControl_DigitalView : UserControl { public static readonly DependencyProperty StrDigitalProperty; public static readonly DependencyProperty StrHighlightProperty; static UserControl_DigitalView() { StrDigitalProperty = DependencyProperty.Register("StrDigital", //属性名称 typeof(string), //属性类型 typeof(UserControl_DigitalView), //该属性所有者,即将该属性注册到那个类上 new PropertyMetadata("")); //属性默认值 StrHighlightProperty = DependencyProperty.Register("StrHighlight", //属性名称 typeof(string), //属性类型 typeof(UserControl_DigitalView), //该属性所有者,即将该属性注册到那个类上 new PropertyMetadata("")); //属性默认值 // DefaultStyleKeyProperty.OverrideMetadata(typeof(UserControl_DigitalView), // new FrameworkPropertyMetadata(typeof(UserControl_DigitalView))); } public string StrDigital { get { return (string)GetValue(StrDigitalProperty); } set { SetValue(StrDigitalProperty, value); } } public string StrHighlight { get { return (string)GetValue(StrHighlightProperty); } set { SetValue(StrHighlightProperty, value); } } public UserControl_DigitalView() { InitializeComponent(); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { ShowView(); } Run GetRun(string digital, string[] digitalHighlight) { Run run = new Run(); int count = digitalHighlight.Where(o => o == digital).Count(); if (count > 0) { run.Background = Brushes.Green; run.Foreground = Brushes.White; } run.Text = digital; return run; } private void ShowView() { string[] digitals = StrDigital.Split(new char[] { ‘ ‘ }, StringSplitOptions.RemoveEmptyEntries); string[] digitalHighlight = StrHighlight.Split(new char[] { ‘ ‘ }, StringSplitOptions.RemoveEmptyEntries); foreach (string digital in digitals) { txtDigital.Inlines.Add(GetRun(digital, digitalHighlight)); txtDigital.Inlines.Add(" "); } } }
txtDigital是TextBlock控件,该控件的Inlines属性可以包含不同字体属性的文字片段。我们需要根据StrDigital,StrHighlight参数填充这些片段。
后记 WPF非常重要的概念就是绑定和模板,这是MVVM模式具体的体现。WPF的控件其实并不多,可能还没WinForm多,但是wpf控件都是可定制的。控件只是定义行为(相当于业务逻辑),控件外观都是可定制,wpf控件可以以一当十;所以一个框架的好坏以控件多少来评判是不公平。本人用业余时间两天开发完成这个程序,可见WPF开发的效率和灵活性之高。
原文地址:https://www.cnblogs.com/yuanchenhui/p/12114117.html