zoukankan      html  css  js  c++  java
  • WPF实现强大的动态公式计算

    数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。

    1、VS2012新建一个WPF应用程序WpfApp_DynCalc,并添加一个类DynCalc.cs,如下图:

     

    2、编辑MainWindow.xaml,代码如下:

      1 <Window x:Class="WpfApp_DynCalc.MainWindow"
      2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      4         Title="WPF动态计算示例" Height="350" Width="525">
      5     <Grid>
      6         <Grid.Resources>
      7         <Style TargetType="DataGrid">
      8             <!--网格线颜色-->
      9             <Setter Property="CanUserResizeColumns" Value="false"/>
     10             <Setter Property="Background" Value="#E6DBBB" />
     11             <Setter Property="BorderBrush" Value="#d6c79b" />
     12             <Setter Property="HorizontalGridLinesBrush">
     13                 <Setter.Value>
     14                     <SolidColorBrush Color="#d6c79b"/>
     15                 </Setter.Value>
     16             </Setter>
     17             <Setter Property="VerticalGridLinesBrush">
     18                 <Setter.Value>
     19                     <SolidColorBrush Color="#d6c79b"/>
     20                 </Setter.Value>
     21             </Setter>
     22         </Style>
     23 
     24         <!--标题栏样式-->
     25         <!--<Style  TargetType="DataGridColumnHeader" >
     26         <Setter Property="Width" Value="50"/>
     27         <Setter Property="Height" Value="30"/>
     28         <Setter Property="FontSize" Value="14" />
     29         <Setter Property="Background" Value="White" />
     30         <Setter  Property="FontWeight"  Value="Bold"/>
     31     </Style>-->
     32 
     33         <Style TargetType="DataGridColumnHeader">
     34             <Setter Property="SnapsToDevicePixels" Value="True" />
     35             <Setter Property="MinWidth" Value="0" />
     36             <Setter Property="MinHeight" Value="28" />
     37             <Setter Property="Foreground" Value="#323433" />
     38             <Setter Property="FontSize" Value="14" />
     39             <Setter Property="Cursor" Value="Hand" />
     40             <Setter Property="Template">
     41                 <Setter.Value>
     42                     <ControlTemplate TargetType="DataGridColumnHeader">
     43                         <Border x:Name="BackgroundBorder" BorderThickness="0,1,0,1" 
     44                              BorderBrush="#e6dbba" 
     45                               Width="Auto">
     46                             <Grid >
     47                                 <Grid.ColumnDefinitions>
     48                                     <ColumnDefinition Width="*" />
     49                                 </Grid.ColumnDefinitions>
     50                                 <ContentPresenter  Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
     51                                 <Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill"  Grid.Column="2" Width="8" Height="6" Fill="White" Margin="0,0,50,0" 
     52                             VerticalAlignment="Center" RenderTransformOrigin="1,1" />
     53                                 <Rectangle Width="1" Fill="#d6c79b" HorizontalAlignment="Right" Grid.ColumnSpan="1" />
     54                                 <!--<TextBlock  Background="Red">
     55                             <ContentPresenter></ContentPresenter></TextBlock>-->
     56                             </Grid>
     57                         </Border>
     58                     </ControlTemplate>
     59                 </Setter.Value>
     60             </Setter>
     61             <Setter Property="Height" Value="25"/>
     62         </Style>
     63         <!--行样式触发-->
     64         <!--背景色改变必须先设置cellStyle 因为cellStyle会覆盖rowStyle样式-->
     65         <Style  TargetType="DataGridRow">
     66             <Setter Property="Background" Value="#F2F2F2" />
     67             <Setter Property="Height" Value="25"/>
     68             <Setter Property="Foreground" Value="Black" />
     69             <Style.Triggers>
     70                 <!--隔行换色-->
     71                 <Trigger Property="AlternationIndex" Value="0" >
     72                     <Setter Property="Background" Value="#e7e7e7" />
     73                 </Trigger>
     74                 <Trigger Property="AlternationIndex" Value="1" >
     75                     <Setter Property="Background" Value="#f2f2f2" />
     76                 </Trigger>
     77 
     78                 <Trigger Property="IsMouseOver" Value="True">
     79                     <Setter Property="Background" Value="LightGray"/>
     80                     <!--<Setter Property="Foreground" Value="White"/>-->
     81                 </Trigger>
     82 
     83                 <Trigger Property="IsSelected" Value="True">
     84                     <Setter Property="Foreground" Value="Black"/>
     85                 </Trigger>
     86             </Style.Triggers>
     87         </Style>
     88 
     89         <!--单元格样式触发-->
     90         <Style TargetType="DataGridCell">
     91             <Setter Property="Template">
     92                 <Setter.Value>
     93                     <ControlTemplate TargetType="DataGridCell">
     94                         <TextBlock TextAlignment="Center" VerticalAlignment="Center"  >
     95                            <ContentPresenter />
     96                         </TextBlock>
     97                     </ControlTemplate>
     98                 </Setter.Value>
     99             </Setter>
    100             <Style.Triggers>
    101                 <Trigger Property="IsSelected" Value="True">
    102                     <!--<Setter Property="Background" Value="White"/>
    103                 <Setter Property="BorderThickness" Value="0"/>-->
    104                     <Setter Property="Foreground" Value="Black"/>
    105                 </Trigger>
    106             </Style.Triggers>
    107         </Style>
    108         </Grid.Resources>
    109 
    110 
    111         <DataGrid  Name="dgrid"   HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="256" Width="498"  AutoGenerateColumns="False" >
    112             <DataGrid.Columns>
    113                 <DataGridTextColumn  Header="指标" Binding="{Binding Zb}" Width="118"/>
    114                 <DataGridTextColumn  Header="值" Binding="{Binding Value}" Width="100"/>
    115                 <DataGridTextColumn  Header="公式" Binding="{Binding Formula}" Width="188"/>
    116             </DataGrid.Columns>
    117         </DataGrid>
    118         <Button Content="计 算" HorizontalAlignment="Left" Margin="419,281,0,0" VerticalAlignment="Top" Width="85" Click="Button_Click_1" Height="28" />
    119         <TextBlock Name="lblResult" HorizontalAlignment="Left" Margin="28,281,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top"/>
    120 
    121     </Grid>
    122 </Window>

    3、编辑后台文件MainWindow.xaml.cs,代码如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Windows;
     7 using System.Windows.Controls;
     8 using System.Windows.Data;
     9 using System.Windows.Documents;
    10 using System.Windows.Input;
    11 using System.Windows.Media;
    12 using System.Windows.Media.Imaging;
    13 using System.Windows.Navigation;
    14 using System.Windows.Shapes;
    15 
    16 using System.Collections.ObjectModel;
    17 namespace WpfApp_DynCalc
    18 {
    19     /// <summary>
    20     /// MainWindow.xaml 的交互逻辑
    21     /// </summary>
    22     public partial class MainWindow : Window
    23     {
    24         public MainWindow()
    25         {
    26             InitializeComponent();
    27 
    28           
    29             ObservableCollection<Dynformula> ofs = new ObservableCollection<Dynformula>();
    30             ofs.Add(new Dynformula { Zb = "A", Value = "1", Formula = "" });
    31             ofs.Add(new Dynformula { Zb = "B", Value = "2", Formula = "2*A+1" });
    32             ofs.Add(new Dynformula { Zb = "C", Value = "3", Formula = "B*B" });
    33             ofs.Add(new Dynformula { Zb = "D", Value = "4", Formula = "C-2" });
    34             ofs.Add(new Dynformula { Zb = "Z", Value = "5", Formula = "D+C" });
    35             this.dgrid.ItemsSource = ofs;
    36          
    37          
    38         }
    39 
    40         private void Button_Click_1(object sender, RoutedEventArgs e)
    41         {
    42             this.lblResult.Text = "计算...";
    43              this.dgrid.ItemsSource=   DynCalc.CalcScript(ref this.dgrid);
    44              this.lblResult.Text = "计算完成!";
    45           
    46         }
    47     }
    48 
    49     public class Dynformula
    50     {
    51         private string zb;
    52 
    53         public string Zb
    54         {
    55             get { return zb; }
    56             set { zb = value; }
    57         }
    58         private string value;
    59 
    60         public string Value
    61         {
    62             get { return this.value; }
    63             set { this.value = value; }
    64         }
    65         private string formula;
    66 
    67         public string Formula
    68         {
    69             get { return formula; }
    70             set { formula = value; }
    71         }
    72 
    73     }
    74 }

    3、编辑类DynCalc.cs,代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 
      7 namespace WpfApp_DynCalc
      8 {
      9 using System.Collections.ObjectModel;
     10 using System.Windows; 
     11 using System.Windows.Controls;
     12 using System.Reflection; 
     13 using System.Globalization; 
     14 using Microsoft.CSharp;
     15 using System.CodeDom; 
     16 using System.CodeDom.Compiler;
     17    public static class DynCalc
     18     {
     19 
     20        public static ObservableCollection<Dynformula> CalcScript(ref DataGrid dgrid)
     21        {
     22          
     23            CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();     
     24            ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
     25            CompilerParameters objCompilerParameters = new CompilerParameters();
     26            objCompilerParameters.ReferencedAssemblies.Add("System.dll");
     27            objCompilerParameters.GenerateExecutable = false;
     28            objCompilerParameters.GenerateInMemory = true;
     29            CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode(ref dgrid));
     30            if (cr.Errors.HasErrors)
     31            {
     32                Console.WriteLine("编译错误:");
     33                foreach (CompilerError err in cr.Errors)
     34                {
     35                    Console.WriteLine(err.ErrorText);
     36                }
     37                return null;
     38            }
     39            else
     40            {
     41                // 通过反射,调用实例
     42                Assembly objAssembly = cr.CompiledAssembly;
     43                object objDynCalc = objAssembly.CreateInstance("DynamicCodeGenerate.RunScript");
     44                //MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
     45                //Console.WriteLine(objMI.Invoke(objHelloWorld, null));
     46 
     47                ObservableCollection<Dynformula> ofsnew = new ObservableCollection<Dynformula>();
     48                //循环datagrid进行公式计算并赋值
     49                for (int i = 0; i < dgrid.Items.Count; i++)
     50                {
     51                    Dynformula item = dgrid.Items[i] as Dynformula;
     52                    if (item == null)
     53                    {
     54                        break;
     55                    }
     56                    string zb = item.Zb;
     57                    PropertyInfo pinfo = objDynCalc.GetType().GetProperty(zb);
     58                    if (pinfo != null && pinfo.CanRead)                   {
     59                        //获取属性get值
     60                        object obj_Name = pinfo.GetValue(objDynCalc, null);
     61                      //  item.Value = obj_Name.ToString();
     62                        ofsnew.Add(new Dynformula { Zb = item.Zb, Value = obj_Name.ToString(), Formula = item.Formula});
     63                    }
     64                }
     65                return ofsnew;
     66            }
     67        }
     68        /// <summary>
     69        /// 计算逻辑C#脚本动态构建
     70        /// </summary>
     71        /// <param name="dgrid">存有指标以及指标计算公式的datagrid</param>
     72        /// <returns>C#脚本</returns>
     73         static string GenerateCode(ref DataGrid dgrid)
     74         {
     75             StringBuilder sb = new StringBuilder();
     76             StringBuilder sb构建函数内容 = new StringBuilder();
     77             sb.Append("using System;");
     78             sb.Append(Environment.NewLine);
     79             sb.Append("namespace DynamicCodeGenerate");
     80             sb.Append(Environment.NewLine);
     81             sb.Append("{");
     82             sb.Append(Environment.NewLine);
     83             sb.Append("    public class RunScript");
     84             sb.Append(Environment.NewLine);
     85             sb.Append("    {");
     86             //------------------------------------------------------------
     87             for(int i=0;i<dgrid.Items.Count;i++)
     88             {
     89                 Dynformula item = dgrid.Items[i] as Dynformula;
     90                 if (item == null)
     91                 {
     92                     break;
     93                 }
     94                 string zb = item.Zb;
     95                 sb.Append(Environment.NewLine);
     96                 sb.AppendFormat("        public double _{0};", item.Zb);
     97                 sb.Append(Environment.NewLine);
     98                 sb.AppendFormat("        public double {0}",item.Zb);
     99                 sb.Append(Environment.NewLine);
    100                 sb.Append("        {");
    101                 sb.Append(Environment.NewLine);
    102               
    103                 if (item.Formula.Trim() != "")
    104                 {
    105                     sb.Append("             set{ "+item.Zb+"=value;}" );
    106                     sb.Append(Environment.NewLine);
    107                     sb.Append("             get{return "+ item.Formula + ";}");
    108                 }
    109                 else
    110                 {
    111                     sb.Append("             set{ _" + item.Zb + "=value;}");               
    112                     sb.Append(Environment.NewLine);
    113                     sb.Append("             get{return  _"+item.Zb+";} ");
    114                     sb.Append(Environment.NewLine);
    115                     sb构建函数内容.Append("       _" + item.Zb + "=" + item.Value);
    116                 }
    117                 sb.Append(Environment.NewLine);
    118                 sb.Append("        }");
    119                 sb.Append(Environment.NewLine);
    120             }         
    121             //--------------------------------------------
    122             //构造函数进行赋值
    123             sb.Append(Environment.NewLine);
    124             sb.Append("        public  RunScript()");
    125             sb.Append(Environment.NewLine);
    126             sb.Append("        {");
    127             sb.Append(Environment.NewLine);
    128             sb.AppendFormat("            {0};",sb构建函数内容.ToString());
    129             sb.Append(Environment.NewLine);
    130             sb.Append("        }");
    131             sb.Append(Environment.NewLine);
    132 
    133             //----------------------------------------------
    134             sb.Append(Environment.NewLine);
    135             sb.Append("        public string OutPut()");
    136             sb.Append(Environment.NewLine);
    137             sb.Append("        {");
    138             sb.Append(Environment.NewLine);
    139             sb.Append("             return "Hello world!";");
    140             sb.Append(Environment.NewLine);
    141             sb.Append("        }");
    142             //-----------------------------------------
    143             sb.Append(Environment.NewLine);
    144             sb.Append("    }");
    145             sb.Append(Environment.NewLine);
    146             sb.Append("}");
    147 
    148             string code = sb.ToString();
    149             Console.WriteLine(code);
    150             return code;
    151         }
    152 
    153     }
    154 }


    4、运行程序,其中值列的值为初始值,点击计算后会根据公式列配置进行动态计算,初始化界面如下:

     5、点击计算后界面如下:

    可见现在的值是根据公式配置进行动态计算的。当然代码经过扩展还可以支持函数和简单的逻辑判断,如if ...else等。实现更强大的逻辑处理。

     

     

     

  • 相关阅读:
    201521123076《java程序设计》第四次总结
    201521123076《java程序设计》第三周学习总结
    201521123076《Java程序设计》第2周学习总结
    软件工程网络15个人阅读作业2
    软件工程网络15个人作业1
    java程序设计----学生基本信息管理系统
    201521123070 《JAVA程序设计》第14周学习总结
    201521123070 《JAVA程序设计》第13周学习总结
    201521123070 《JAVA程序设计》第12周学习总结
    201521123070《Java程序设计》 第11周学习总结
  • 原文地址:https://www.cnblogs.com/isaboy/p/dynamicCalc.html
Copyright © 2011-2022 走看看