用WPF山寨折线图,抄?是狠狠的抄

news2023/12/12 3:36:58

     对于没有美术细胞的我来说,抄袭人家的设计或是创意是再平常不过的事,我承认这很无耻,如果在伟大“天朝”的教育体系下还可能升级为道德上的沦丧,毕竟人家搞个东西也不容易,可任务在身,只好下策,脸皮总是在生存以后才拿上台面的。所以也就不避讳了,俺就是抄的。

     2010032418543844

     该图抄袭自 万仓一黍 的在winform中运用FusionCharts图表(一)

 

一.抄袭模式

 

        尽管样式要抄袭,可代码不能抄袭,因为没有源码^ – ^ 。首先我们先从使用者的角度出发,作为使用者,我希望怎么来使用控件,而且要考虑到WPF的一些特性。线条可以一个个数组给,和传统的控件一样。可我认为这并不符合WPF的组装特性,每个线条可以是自由控制的,可粗可细,可虚线可实线。

如效果为这样的图:

image

 

可以是这样的设计,也就是每个控件自己是一层,和其它控件没有直接联系。就连底面也是可以自由搭配的。

image image

使用还有个就是代码的书写,那么在XAML中单个的控件就可以写成这样

<Sample:LineChart LineColor="Orange" LineThickness="20" Datas="{Binding Items}" />

如若要实现多个拼接,把控件放到可以层叠的容器当中就可以了,比如Grid.如果你的数据是集合形式的,还可以借助ItemsControl这样的集合控件。

      这里可能已经有人看出来抄袭的是WPF装饰器的模式和概念。

 

二.抄袭图形

 

      初步设想不错,可还不够灵活,假设每个点的样式可以更改而不仅仅是这种默认的白点,如根据喜好可以设置五角星,小红旗,这怎么办?一般情况下我们会为控件再添加个点的模板属性;在这里我又踟蹰了很久,是否真的需要这么的“一步到位”?在几年前,我曾听说装修现在有个观点叫做“轻装修,重装饰”,就是建好一个架子,里面的东西是可以由着喜好、心情、季节随意搭配。所以我更倾向于控件首先能实现一些比较简单的功能,可如果要更高级的功能和效果应该可以附加上的,毕竟有时候一开始也很难知道用户的喜好,加上有时候时间紧迫就只能先留下框架,以后有机会再讨价还价索要时间。

      产品功能暂时可以延期,却不能老是跳票,“永远的毁灭公爵”绝不是好榜样。

      对每个点进行模板,设置每个点实际的位置,很容易让我们想到使用ItemsControl,做个放置位置的Panel就可以了, 当然很明显我们并不需要那么多的功能,只要求每个点都能设置一个模板,那么好吧,依葫芦画瓢来个ItemTemplate、ItemTemplateSelector、ItemStringFormat属性,只需要在初始化的时候声明个UIElementCollection变量,在数据存放以后为数据new个性模板就成,如GetContainerForItemOverride()方法。

     在这种条件下做个层,可以轻松的看到类似这样的效果,当然音符是我再次发挥抄袭特长的结果,具体的可以看http://xamlbase.com/free-icons.php

image

对于层来说,还可以有很多的发挥,如下:

image

对这种应用也可以手到擒来:

image

不要惊讶,WPF是有API的,使用CombinedGeometry然后用GeometryCombineMode.Exclude就可以了。

因为底色也可以随意混搭,所以加个水印、Logo,背景提示语之类的也不是什么难事。

对于以上的所谓“创意”,当然是抄袭的,参见各大网站统计图。

 

三.抄袭代码

 

       项目经理有要求图上的所有线条比例要统一,这个要求很合乎常理,可我们的线条都是单独的一个控件,你也许会说让后端计算出一个最大值绑定一下不就OK了,但一般控件都可以达到的效果,凭什么就要让业务干预,毕竟我们分层的原则是UI和业务分离,虽然有时候会有些妥协,但我们也要尽可能的做大完善,水平不就是在这样的“苛责”中进步的么?

 

感觉不错的抄法

▲名字抄袭

      做为前端人员,可能希望只要设置一个属性就可以完成,其实它的目的就是为了功能的附加,感觉有点像ToolTipService吧,那么我们的名字就叫LineChartService

<Sample:LineChart LineColor="Orange" Sample:LineChartService.GroupName="group1" LineThickness="2" Datas="{Binding Items}" />
<Sample:LineChart LineColor="Green"  Sample:LineChartService.GroupName="group1" LineThickness="2"  Datas="{Binding Items1}" />

 

▲做法抄袭

    这种方法是方便,可作为后端的编码人员应该怎么做呢?印象中第一个出现的类似应用可能就是RadioButton,因为它也有个GroupName,可以根据组来决定勾选的控件影响的范围,好吧看看它的源码是如何做到的的,其实所谓的看就是一个大抄袭,去其特质取其共性。

 

▲算法抄袭

     在抄袭这一模式的时候,有个想法就是计算出每个控件的最大值,然后放到一个全局的队列中,这个队列有自动排序功能,并有一个属性可以取得最大值.这其实是个算法,这个算法哪有的抄呢?当时在看BeginInvoke,我们的DispatcherPriority放进去,系统会根据值的大小排序,每次有个属性可以取得最大值,这不正是我所期望的么,啥都不说了,直接Copy,当然也要去掉一些东西,这种简单的算法,只要理解了他的目的,也没啥难度。所以PriorityQueue这个内部类也被我惨无人道的抄袭了。

 

▲WPF特性应用抄袭

     对于屏幕的笛卡尔坐标,和我们普通的坐标不同,越向下Y轴值越大,一般的做法是用高度值来减下,以符合需求,可在WPF有Transform,在最后绘制图形的时候用这个来包装下,个人认为更优雅,这一做法抄袭自donjuan的在WPF中使用ItemsControl控件来实现线状图控件(一)

drawingContext.PushTransform(new ScaleTransform(1, -1, 0, RenderSize.Height / 2));
…
drawingContext.Pop();

 

不爽的抄法

      在为点应用模板的代码中,最邪恶的应该是以下的一段山寨成果,声明这一坨真不是我的原创,打这一段也打的我老郁闷了,具体可以参看ItemsContorl中的做法。

protected virtual void PrepareContainerForItemOverride(DependencyObject element, double item)
{
    var headeredContentControl = element as HeaderedContentControl;
    if (headeredContentControl != null)
    {
        headeredContentControl.Content = item;
        headeredContentControl.ContentTemplate = ItemTemplate;
        headeredContentControl.ContentTemplateSelector = ItemTemplateSelector;
        headeredContentControl.ContentStringFormat = ItemStringFormat;
    }
    else
    {
        var contentControl = element as ContentControl;
        if (contentControl != null)
        {
            contentControl.Content = item;
            contentControl.ContentTemplate = ItemTemplate;
            contentControl.ContentTemplateSelector = ItemTemplateSelector;
            contentControl.ContentStringFormat = ItemStringFormat;
        }
        else
        {
            var contentPresenter = element as ContentPresenter;
            if (contentPresenter != null)
            {
                contentPresenter.Content = item;
                contentPresenter.ContentTemplate = ItemTemplate;
                contentPresenter.ContentTemplateSelector = ItemTemplateSelector;
                contentPresenter.ContentStringFormat = ItemStringFormat;
            }
            else
            {
                var headeredItemsControl = element as HeaderedItemsControl;
                if (headeredItemsControl != null)
                {
                    headeredItemsControl.Header = item;
                    headeredItemsControl.HeaderTemplate = ItemTemplate;
                    headeredItemsControl.HeaderTemplateSelector = ItemTemplateSelector;
                    headeredItemsControl.HeaderStringFormat = ItemStringFormat;

                }
                else
                {
                    ItemsControl itemsControl;
                    if (((itemsControl = element as ItemsControl) != null))
                    {
                        itemsControl.ItemTemplate = ItemTemplate;
                        itemsControl.ItemTemplateSelector = ItemTemplateSelector;
                        itemsControl.ItemStringFormat = ItemStringFormat;
                    }
                }
            }
        }
    }
}

微软的类似的代码其实并不是最令人愤慨的,大批的internal才是令人反胃的,so,我也就一同copy了这风格。

 

四.补充

 

2006101510830284

       对于折线图的应用还可以有线条的动画呈现,点的动画变动,点的手动拖拉,大数据虚拟化显示等等,这些都可以发挥自己的想象做出更美好的作品,但您也可以抄袭一些现有的控件来达到需求。总之我们“学习”、“参考”都是希望有一天那些东西能够为我们效劳,对于类似左边图上的效果也很容易抄袭得到。

       如果您下了我的代码,可能会发现所提供的控件,似乎“只可远观不可亵玩”,很多功能貌似都被阉割了。比如:默认阴影的两头只是简单的处理,阴影里没有圆形的倒影,看起来不真实,默认的圆圈半径和外框线当值设大时会有问题(控件的Pen的Thickness的线的中点落在给定圆的半径上,而不是在半径外有Thickness),GroupName只处理了最大值而未处理最小值,PointLayer控件所产生的模板好像并未和原来的点重合,这么多控件有些方法居然没有提成公用方法等等。首先我得承认这些问题都是刚开始疏忽了,如果您能放弃那些控件而用自己的方式进行山寨,改份更好的,BUG更少的,更易用的,我想您的心情会更好。

       回顾这些年的程序员生涯,让我感慨最深的就是复制和粘贴,从最初的Hello World到WPF的学习,一路上就是Sample的抄袭和应用,整个过程都是在别人路上进行徘徊,模式是别人的,语言是别人的,用法也是别人规定的,跌撞中偶尔发现个技法,也是在使用别人的API下,日复一日我都产生了做软件如同搭积木的消极想法。可其实人的物质生活,思想文化又是怎么提高的呢?可以说是站立在伟人的肩膀上,也可以说是把别人发现的路拓展的更好的基础上,生活也就在这一点点变化中,愈加美好。当然,您得拥有一颗不满现状积极向上的心。

      

PS:因抄袭产生的RP问题概不负责,毕竟上个月俺已经丢了饭卡一张,门进卡一张,手机一部,手机卡补的时候还多花了30元。

附件  尽管我们是同道中人,还是希望您不会再要刻度尺,因为我也没有^^

转载于:https://www.cnblogs.com/Curry/archive/2010/04/02/LineChart.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.cn/news/show-830745.html

如若内容造成侵权/违法违规/事实不符,请联系七分地网进行投诉反馈,一经查实,立即删除!

相关文章

PyCharm编写shell脚本无法运行

背景 我们常常选择使用PyCharm在本地&#xff08;Windows&#xff09;进行开发&#xff0c;然后将文件远程同步到远程服务器&#xff08;Linux&#xff09;运行程序&#xff0c;但是这样编写的shell脚本常常无法运行&#xff0c;出现语法错误&#xff0c;因为好几个朋友和我提…

返回局部变量或临时变量的地址_值传递和地址返回两者在堆区(Heap)应用的三种易错点...

1、指针变量作为参数进行值传递给函数的形参&#xff0c;并在堆区(Heap)进行内存分配和赋值程序源码&#xff1a;1 结果&#xff1a;Segmentation fault (core dumped)分析&#xff1a;如上图&#xff0c;指针变量ptr进行值传递给函数allocation()的形参tmp并赋值为NULL&#x…

微服务通信带来的问题

有了远程通信以后&#xff0c;我们势必会考虑几个问题 1. 目标服务肯定会做扩容&#xff0c;扩容以后&#xff0c;客户端会带来一些变化 2. 客户端对于目标服务如何进行负载均衡 3. 客户端如何维护目标服务的地址信息 4. 服务端的服务状态变化&#xff0c;如何让客户端尽心…

牛客多校10 - Tournament(找规律)

题目链接&#xff1a;点击查看 题目大意&#xff1a;现在有 n 个队伍参加比赛&#xff0c;任意两个队伍之间都要进行一次比赛&#xff0c;也就是共需要进行 n * ( n - 1 ) / 2 次比赛&#xff0c;对于每个队伍来说&#xff0c;必须要在第一场比赛的时候到达赛场&#xff0c;在…

Zend API: array_init

为什么80%的码农都做不了架构师&#xff1f;>>> array_init 和array_init_size 这2个看起来像是个函数其实这2个都是宏&#xff0c;具体定义在文件&#xff1a;zend_API.h 中。 #define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC) #define array…

pvbrowser安装教程(Linux)

简介 pvbrowser是一款基于QT的开源组态软件开发框架&#xff0c;它为客户端计算机提供了一个专门的浏览器&#xff0c;并为创建实现可视化的服务器提供了一个集成开发环境。不过&#xff0c;官方文档对于pvbrowser开发环境的配置写的略微有点草率&#xff0c;本文给出Ubuntu下…

tensorflow官方文档_Tensorflow 2.0 Preview 官方文档

TensorFlow 2.0目前放出了Preview版本。目前想了解TensorFlow 2.0最快的方式就是查看官方API中的变化。本文列举一些从TF官方API中看出的TF 2.0的改进。TensorFlow 2.0 Preview可以通过pip下载了:CPU: https://pypi.org/project/tf-nightly-2.0-preview/GPU: https://pypi.org/…

Android ---- Context

Context字面意思上下文&#xff0c;位于framework package的android.content.Context中&#xff0c;很多方法需要通过  Context才能识别调用者的实例&#xff0c;比如说Toast的第一个参数就是Context&#xff0c;一般在Activity中我们直接用this代替&#xff0c;代表调用者的 …

Linux进程详细信息查看

我们通过ps及top系列命令查看进程信息时&#xff0c;只能看到命令执行的相对路径&#xff0c;查不到的进程的详细信息&#xff08;如绝对路径&#xff09;&#xff0c;那么这些信息到底如何查找呢&#xff1f; 其实&#xff0c;在Linux中&#xff0c;一切皆文本&#xff0c;那…

python操作json_如何使用Python处理JSON数据

如何使用Python处理JSON数据&#xff1f;本篇文章就给大家介绍使用Python处理JSON数据的基本方法。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你们有所帮助。 在介绍使用Python处理JSON数据的基本方法之前&#xff0c;我们首先要了解一下什么是J…

面试题——interleave

2019独角兽企业重金招聘Python工程师标准>>> <!-- lang: cpp --> /** *3个字符串a&#xff0c;b&#xff0c;c。判断c是否是a和b的interleave&#xff0c;也就是c中应该有a&#xff0c;b中所有字符&#xff0c; *并且c中字符顺序和a&#xff0c;b中一样。 *比…

corosync/openais+pacemaker+drbd+web实现高可用群集

拓扑图:配置前提&#xff1a; 1.节点的名字必须跟uname -n的名字相同&#xff0c;而且两个主机必须能通过主机名来访问。尽量不通过DNS来访问。时钟时间保持一样。 2.双方的通信要必须通过SSL的无障碍通信机制 3.双节点之间可以通过某个IP来提供连接&#xff0c;但是这只是通信…

0459-Repeated Substring Pattern(重复的子字符串)

这个系列算是出于个人兴趣开的一个新坑吧&#xff0c;最近看到同学刷LeetCode算法题&#xff0c;就想写写那些可以一行Python代码写出来的题目&#xff0c;因此本专栏的文章的解题方式效率不做保证&#xff0c;只为追求“一行的浪漫”。 题目 题解 简单解释一下题目&#xff0…

golang 反射_golang原理篇- nil:接口类型和值类型的区别

interface接口类型是golang的最重要的数据结构&#xff0c;底层是value和type组成&#xff0c;实现interface的struct的实例都能赋值给接口类型的变量&#xff0c;实现动态value的能力。type记录value的类型。int 3 的接口表示是(int, 3)&#xff0c;接口的零值是 (nil, nil)&a…

分布式一致性问题

什么是分布式一致性问题呢&#xff1f;简单来说&#xff0c;就是在一个分布式系统中&#xff0c;有多个节点&#xff0c;每个节点都会提出一个请求&#xff0c;但是在所有节点中只能确定一个请求被通过。而这个通过是需要所有节点达成一致的结果&#xff0c;所以所谓的一致性就…

can1--can初探

updating http://download.csdn.net/detail/songqqnew/4399668 http://download.csdn.net/detail/songqqnew/4399670http://download.csdn.net/detail/songqqnew/4399684mcp2515寄存器一览 几个寄存器名称及地址 TXBnCTRL——发送缓冲器n 控制寄存器&#xff08;地址&#xff1…

Michael Nygard on Building Resilient Systems

原文 InfoQ.Feature Complete Software 和 Production Ready Software是不同的。而很多时候&#xff0c;开发人员不清楚Production下的情况&#xff0c;所以没有很好的考虑到在Production下运行的情况。例如&#xff0c;在开发环境下&#xff0c;Sever A和Server B的压力是 1&…

python开发_tkinter_单选按钮

这篇blog主要是描述python中tkinter的单选按钮操作 下面是我做的demo 运行效果&#xff1a; 代码部分&#xff1a; 1 from tkinter import *2 3 # This is a demo program that shows how to4 # create radio buttons and how to get other widgets to5 # share the informat…

多继承有什么坏处,为什么java搞单继承,接口为什么可以摈弃这些坏处

2019独角兽企业重金招聘Python工程师标准>>> 多继承虽然能使子类同时拥有多个父类的特征&#xff0c;但是其缺点也是很显著的&#xff0c;主要有两方面&#xff1a; (1)如果在一个子类继承的多个父类中拥有相同名字的实例变量&#xff0c;子类在引用该变量时将产生歧…

提取身份证信息-阶段1 图像处理

目标 为了实现pc端&#xff0c;提取一张拍摄的身份证照片中人物的信息&#xff0c;照片背景单一且为浅色&#xff0c;初步使用图像处理知识进行处理。 由浅入深&#xff0c;第一步&#xff0c;使用简单的图片&#xff0c;并且有针对性的对某幅图片进行针对性处理&#xff0c;得…