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等。实现更强大的逻辑处理。

时间: 2024-10-14 15:50:22

WPF实现强大的动态公式计算的相关文章

【Windows 10 应用开发】使用x:Bind标记动态获得计算结果

UWP 在传统(WPF)的Binding标记上引入了 Bind 标记,Bind 基于编译阶段生成,因而具有较高的性能.但是,你得注意,这个性能上的优化是免去了运行阶段动态绑定的开销,这是不包括数据源的体积的.要是你的数据源本身很大的话,那是没办法优化的,只能靠你自己想办法,尽可能把加载到内存中的数据缩小,比如你只加载300条,不要一下子就读几万条数据.当然也可以使用增量加载方案. Bind 标记还有一个特色——可以绑定事件处理方法和常规方法,可以给绑定的方法传递参数.比如有这样一个方法: int

[转]EXCEL如何使用动态公式

本文转自:http://tech.cncms.com/ruanjian/office/excel/95440.html 也许大家可能还不知道Excel中的动态公式是什么,所谓的动态公式,不是普通的公式,而是更好灵活的公式的使用方法.下面就给你举例来说明. 一.构造动态公式 在EXCEL某个工作表中,如果随时查看某个动态区域的统计结果,可以设计动态公式: 在某个单元格中输入函数式:=AVERAGE(INDIRECT(数据统计区域的开始位置标记):INDIRECT(数据统计区域的结束位置标记)) 比

用python实现计算1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))类似的公式计算

作业需求: 开发一个简单的python计算器 1.实现加减乘除及拓号优先级解析 2.用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致 上图是实现的逻辑思路图,下面是对上图的分析: 整体的思想就是先匹配最

c语言详解  蔡勒(Zeller)公式计算某一天是星期几  极其方便

—— 蔡勒(Zeller)公式 历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和一些分段计算公式),其中最著名的是蔡勒(Zeller)公式.即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 公式中的符号含义如下,w:星期:c:世纪-1:y:年(两位数):m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1.2月要看作上一年的13.14月来计算,比如2003年1月1日要看作2002年的13月1日来计算):d:日:[ ]代

C#动态表达式计算

应该有不少人开发过程中遇到过这样的需求,我们直接看图说话: 如上图所示,其中Entity为实体类,其中包括五个属性,该五个属性的值分别来自于数据库查询结果: 用户通过可视化界面进行某些条件的配置以及某些算法的配置并自动生成表达式或者生成数学模型: 程序中需要通过生成的表达式以及动态从数据库中获取的数据进行算法映射以及自动计算出结果. 该需求这边可以举出几个应用场景: 1.报表设计器 我们可以通过报表设计器设计数据库的映射关系并配置数据之间的算法关系,然后动态生成报表: 2.某些采集工具 定向采集

深入浅出Mybatis系列(九)---强大的动态SQL(转载)

原文出处:http://www.cnblogs.com/dongying/p/4092662.html 上篇文章<深入浅出Mybatis系列(八)---mapper映射文件配置之select.resultMap>简单介绍了mybatis的查询,至此,CRUD都已讲完.本文将介绍mybatis强大的动态SQL. 那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误.Myba

【Zeller公式计算星期几】HDU 6112 今夕何夕

acm.hdu.edu.cn/showproblem.php?pid=6112 [思路] 公式计算即可,注意特判2月29号 Zeller公式里,计算出的week不能直接模7,要保证week是正数 [AC] 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath&g

基姆拉尔森公式--计算日期周几

基姆拉尔森公式计算日期周几 #include <iostream> using namespace std; string week[] ={"Mon","tue","Wen","Thu","Fri","Sat","Sun"}; int main(){ int y,m,d; while(cin>>y>>m>>d){ if

使用Machin公式计算

使用Machin公式计算,并使用百亿进制+末项位数控制,这里可算出数万位(比最简PI快80倍),源代码约40行,在本网页中. 计算公式 PI=16arctg(1/5)-4arctg(1/239),其中arctg(x)=x-x^3/3+x^5/5-x^7/7+x^9/9... 令X=x^2并提取公因式得:arctg(x)=x(1-X(1/3-X(1/5-X(1/7-X(…,只需迭代b=1/(2n+1)-b*X,n=N,…,3,2,1,0,最后算b*x即得arctg(x) 要想快速计算几十万位或几百