最近在研究WPF下绘制K线图的功能,由于WPF下图表控件很少,且大多都是收费的,如果自己从头开始写比较复杂,所以在网上看到了这篇文章,WPF中使用amCharts绘制股票K线图 年代比较久远,他用的是amCharts Stock Chart for WPF这个控件,但这个现在看来已经不维护了,或者找不到更新了。于是下载了上文中的代码,研究了一下其中的 AmCharts.Windows.Stock.dll。

    C#程序如果不进行加密或者混淆,是可以使用一些反编译工具直接查看源代码的,比如在.NET开源之前,我们可以直接借助一些工具比如Reflector查看.NET的源代码。我这里先抱着试一试的想法,先用Reflector查看一下这个dll,看能否查看源代码。

使用.NET Reflector


    .NET Reflector这个工具,想必大家都很熟悉,使用方法也很简单,直接打开,然后指定到要查看的dll即可。

     可以看到,这个dll并没有加密,能够直接查看dll,更进一步,这个工具可以支持直接导出源代码:

    这里,点击Export Source Code,就能直接导出源代码。

    这里有个问题是,用.NET Reflector导出的源代码可能会有一些错误提示,需要我们自己进行修复,而且有时还会遇到各种问题。

  • 生成的源代码文件结构和命名空间都很奇怪,需要我们自己调整。
  • 直接生成的代码可能会报很多语法错误,另外由于命名空间的奇怪嵌套,可能会出现有些对象找不到定义的情况,需要重新组织命名空间。
  • 对于WPF程序,对xaml文件以及资源文件的反编译欠缺支持,这个是致命的,会导致源代码即使能编译通过,可能也无法正确运行,会报一些语法错误,比如XamlParseException。

     在修复完这些错误,在调试的时候即使项目文件是Debug模式,在调试时仍然会报无法调试Release,原因是需要移除Properties文件夹AssemblyInfo.cs文件中的这一句代码:

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]

      这就是.NET Reflector遇到的问题,作为一个工具用来查看程序源代码可以,但是直接反编译,可能还是会遇到一些麻烦。

大杀器ILSpy


   ILSpy是开源的,可以直接在Github上下载一个最新的Release版本然后在本机安装,它的操作界面跟.NET Reflector很相似。

    首先打开需要反编译的dll,然后在右键菜单里直接点击保存代码就可以了。导出来的代码里面,比如文档结构,XAML文件,资源文件等等都非常完美,直接使用Visual Studio打开就能编译通过。相当完美。

      有了源代码之后,就能自己进行修改了,正如代码里的license.txt所说,这个dll是一个商业软件。在使用的时候,如果没有购买license,在左上角会显示注册地址的logo。

    这个问题,原博主调研后发现他只会在第一个chart里显示,所以进行了一个巧妙的回避,就是建一个空的chart,然后将其隐藏。

stockChart.Charts[0].Collapse();

    因为我有源码,所以最简单的方法就是,直接修改代码:

     这里需要说明:我们一定要遵守著作权法,否则带来的251后果自负。😂

     修改之后,这个左上角的注册地址就没有啦。

    可以说是相当完美。

    虽然这个K线图出来的,但其实还有很多细节需要调整,比如下方成交量的Y坐标的值,比如鼠标移上去的效果,这些都需要调整,我这里贴出xaml的页面,供大家参考。

<Window x:Class="StockAnalyse.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Stock Analyse" Height="450" Width="700" xmlns:ams="http://schemas.amcharts.com/stock/wpf/2009/xaml" xmlns:stockanalyse="clr-namespace:StockAnalyse" Loaded="Window_Loaded">
    <Grid Margin="10,0,10,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Label Margin="0,5,0,5" Content="打开:"></Label>
            <TextBox Name="txtFilePath" Margin="0,5,0,5" Width="250" Height="22"></TextBox>
            <Button Name="btnOpenFile" Margin="10,5,0,5" Width="30" Content="..." Height="24"
                    Click="btnOpenFile_Click">
            </Button>
        </StackPanel>

        <ams:StockChart Name="stockChart" Grid.Row="1" PlotAreaBackground="#111111"
                        Foreground="White" ZoomModifierKeys="Ctrl" ZoomInOnWheelDown="True" 
                        BalloonBackground="Aqua" PeriodSelectorVisibility="Hidden" ScrollerVisibility="Visible">
            <ams:StockChart.DataSets>
                <ams:DataSet Name="stockSet1" Brush="#7f8da9"
                                ItemsSource="{Binding Data}"
                                DateMemberPath="date"
                                OpenMemberPath="open" HighMemberPath="high"
                                LowMemberPath="low" CloseMemberPath="close"
                                ValueMemberPath="close" VolumeMemberPath="volume"
                                />
            </ams:StockChart.DataSets>
            <ams:StockChart.Charts>
                <ams:Chart  Title="股票价格" GridHeight="2*" PlotAreaBackground="Black" ShowEventBalloons="False">
                    <ams:Chart.Graphs>
                        <ams:Graph GraphType="Candlestick" 
                                    NegativeBrush="#00FD00" PositiveBrush="Red" 
                                    LegendItemType="Ohlc" LegendPeriodItemType="Ohlc"
                                    CursorBrush="Blue" CursorSize="6"/>
                    </ams:Chart.Graphs>
                    <ams:Chart.LeftValueAxis>
                        <ams:ValueAxis Name="PriceChartLeftValueAxis" ValuesForeground="#CCCCCC"  StrokeThickness="0" TickLength="0" ValuesInside="True"  />
                    </ams:Chart.LeftValueAxis>
                    <ams:Chart.LeftValueAxisGrid>
                        <ams:ValueGrid  Stroke="#111111"  >
                        </ams:ValueGrid>
                    </ams:Chart.LeftValueAxisGrid>
                    <ams:Chart.DateTimeAxis>
                        <ams:DateTimeAxis ValuesForeground="#CCCCCC"  StrokeThickness="0" TickLength="0"  />
                    </ams:Chart.DateTimeAxis>

                    <ams:Chart.DateTimeAxisGrid>
                        <ams:DateTimeAxisGrid Stroke="#111111"  />
                    </ams:Chart.DateTimeAxisGrid>
                    <ams:Chart.Legend>
                        <ams:Legend
                            PositiveValueForeground="Red" NegativeValueForeground="#00FD00"
                            IsDateVisible="True"/>
                    </ams:Chart.Legend>
                </ams:Chart>
                <!--成交量的Chart-->
                <ams:Chart Title="成交量" PlotAreaBackground="Black">
                    <ams:Chart.Graphs>
                        <ams:Graph GraphType="Column"
                                    LegendItemType="Value" LegendPeriodItemType="Value"
                                    DataField="Volume" PeriodValue="Sum"
                                    CursorBrush="Blue" CursorSize="6" PositiveBrush="Red" NegativeBrush="#00FD00"
                                    />
                    </ams:Chart.Graphs>
                    <ams:Chart.DateTimeAxis>
                        <ams:DateTimeAxis ValuesEnabled="False" StrokeThickness="0" />
                    </ams:Chart.DateTimeAxis>
                    <ams:Chart.DateTimeAxisGrid>
                        <ams:DateTimeAxisGrid Stroke="#111111"  />
                    </ams:Chart.DateTimeAxisGrid>
                    <ams:Chart.LeftValueAxis>
                        <ams:ValueAxis ValuesForeground="#CCCCCC"  StrokeThickness="1" TickLength="1" />
                    </ams:Chart.LeftValueAxis>
                    <ams:Chart.LeftValueAxisGrid>
                        <ams:ValueGrid  Stroke="#111111"  >
                        </ams:ValueGrid>
                    </ams:Chart.LeftValueAxisGrid>
                    <ams:Chart.Legend>
                        <ams:Legend PositiveValueForeground="Red" NegativeValueForeground="Cyan" />
                    </ams:Chart.Legend>
                </ams:Chart>
            </ams:StockChart.Charts>
        </ams:StockChart>
    </Grid>
</Window>

      后台代码直接查看文章开头博文里的即可,我这里不放出源码了。

      amCharts Stock Chart for WPF这个控件用来绘制股票图形还是可以的,但是他缺少文档,基本的使用方法可以看文章开头的那篇博文。有了源代码之后就能更好的进行定制化修改了,如何进一步使用了进行探索。

总结


    WPF下图形控件很少,第三方的图形控件虽然强大但是大部分是要收费的。本文在前人的使用amCharts Stock Chart for WPF来绘制K线图的基础上,对这个控件使用ILSpy进行了源码反编译,可以对它的代码进行学习以及进一步修改以满足自己的要求。

 

参考资料: