标签:
数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。
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等。实现更强大的逻辑处理。
标签:
原文地址:http://www.cnblogs.com/isaboy/p/dynamicCalc.html