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