很多情况下,我们需要对界面上的元素进行拖动,用鼠标在VS中biaji,biaji,biaji,点几个事件,然后再写出一堆代码,浪费时间不说,由IDE自动生成的那些代码实在是太难看,影响心情。本文使用扩展方法,对于这类行为需要进行封装,以使代码更简单简洁。

封装原则如下:

(1)要简单,最好是一行代码就搞定;

(2)要强大,能用于尽量多的类;

(3)要灵活,可适用于尽量多的场景。

在本文的末尾添加了修改版,修改版代码更简洁,操作更简单,且可以设置多个拖动逻辑。

====

设计下面的扩展方法原型:

public static void SetDraggable(this UIElement element, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)

element 是拖动的界面元素,relativeTo 是参照物,moveCallback 是移动过程中的回调方法。DraggableContext 是一个类,包装了调用方所需要的信息。beforeDragCallback 是拖动前的处理,假设要拖动一个TextBlock,拖动前可以将它改变颜色,以示醒目。afterDragCallback 是拖动结束后的处理。

DraggableContext 的代码为:

public class DraggableContext
{
    public DependencyObject Owner { get; private set; }
    public IInputElement RelativeTo { get; private set; }
    public Point StartPoint { get; internal set; }
    public Point EndPoint { get; internal set; }

public Point Offset
    {
        get { return new Point { X = EndPoint.X - StartPoint.X, Y = EndPoint.Y - StartPoint.Y }; }
    }

private Boolean _dragging;

public Boolean Dragging
    {
        get { return _dragging; }
        internal set
        {
            if (value != _dragging)
            {
                _dragging = value;
                if (value == true)
                {
                    if (BeforeDragCallback != null)
                        BeforeDragCallback(this);
                }
                else
                {
                    if (AfterDragCallback != null)
                        AfterDragCallback(this);
                }
            }
        }
    }

public Action<DraggableContext> MoveCallback { get; private set; }

public Action<DraggableContext> BeforeDragCallback { get; private set; }

public Action<DraggableContext> AfterDragCallback { get; private set; }

public DraggableContext(DependencyObject owner, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
    {
        Owner = owner;
        RelativeTo = relativeTo;
        MoveCallback = moveCallback;
        BeforeDragCallback = beforeDragCallback;
        AfterDragCallback = afterDragCallback;
    }

public override int GetHashCode()
    {
        return Owner.GetHashCode();
    }
}

然后,还需要一个Dictionary,来储存所有的调用者:

  private static Dictionary<Object, DraggableContext> _dicDragContext = new Dictionary<Object, DraggableContext>();

然后,是对拖动逻辑的实现:

public static void SetDraggable(this UIElement element, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
{
    if (element == null) throw new ArgumentNullException("element");

_dicDragContext[element] = new DraggableContext(element, relativeTo, moveCallback, beforeDragCallback, afterDragCallback);
    element.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
    element.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
    element.MouseLeave += new System.Windows.Input.MouseEventHandler(element_MouseLeave);
    element.MouseMove += new System.Windows.Input.MouseEventHandler(element_MouseMove);
}

private static void element_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    _dicDragContext[sender].Dragging = false;
}

private static void element_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    DraggableContext ctx = _dicDragContext[sender];
    ctx.Dragging = true;
    ctx.StartPoint = e.GetPosition(ctx.RelativeTo);
    ctx.EndPoint = ctx.StartPoint;
}

private static void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
    _dicDragContext[sender].Dragging = false;
}

private static void element_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
    DraggableContext ctx = _dicDragContext[sender];
    if (ctx.Dragging == true)
    {
        ctx.Dragging = true;
        ctx.EndPoint = e.GetPosition(ctx.RelativeTo);
        if (ctx.MoveCallback != null)
        {
            ctx.MoveCallback(ctx);
        }
        ctx.StartPoint = ctx.EndPoint;
    }
}

最后,还需要提供一个扩展方法清除对对象和事件的引用,以避免出现内存泄漏。这个方法需要显示调用。

public static void UnsetDraggable(this UIElement element)
{
    element.MouseLeftButtonDown -= new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
    element.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
    element.MouseLeave -= new System.Windows.Input.MouseEventHandler(element_MouseLeave);
    element.MouseMove -= new System.Windows.Input.MouseEventHandler(element_MouseMove);

if (_dicDragContext.ContainsKey(element)) _dicDragContext.Remove(element);
}

完整代码如下:

代码

  1  using  System;
  2  using  System.Collections.Generic;
  3  using  System.Linq;
  4  using  System.Text;
  5  using  System.Windows;
  6  using  System.Windows.Controls;
  7 
  8  namespace  Orc.Util
  9  {
 10       public   class  DraggableContext
 11      {
 12           public  DependencyObject Owner {  get ;  private   set ; }
 13           public  IInputElement RelativeTo {  get ;  private   set ; }
 14           public  Point StartPoint {  get ;  internal   set ; }
 15           public  Point EndPoint {  get ;  internal   set ; }
 16 
 17           public  Point Offset
 18          {
 19               get  {  return   new  Point { X  =  EndPoint.X  -  StartPoint.X, Y  =  EndPoint.Y  -  StartPoint.Y }; }
 20          }
 21 
 22           private  Boolean _dragging;
 23 
 24           public  Boolean Dragging
 25          {
 26               get  {  return  _dragging; }
 27               internal   set
 28              {
 29                   if  (value  !=  _dragging)
 30                  {
 31                      _dragging  =  value;
 32                       if  (value  ==   true )
 33                      {
 34                           if  (BeforeDragCallback  !=   null )
 35                              BeforeDragCallback( this );
 36                      }
 37                       else
 38                      {
 39                           if  (AfterDragCallback  !=   null )
 40                              AfterDragCallback( this );
 41                      }
 42                  }
 43              }
 44          }
 45 
 46           public  Action < DraggableContext >  MoveCallback {  get ;  private   set ; }
 47 
 48           public  Action < DraggableContext >  BeforeDragCallback {  get ;  private   set ; }
 49 
 50           public  Action < DraggableContext >  AfterDragCallback {  get ;  private   set ; }
 51 
 52           public  DraggableContext(DependencyObject owner, IInputElement relativeTo, Action < DraggableContext >  moveCallback  =   null , Action < DraggableContext >  beforeDragCallback  =   null , Action < DraggableContext >  afterDragCallback  =   null )
 53          {
 54              Owner  =  owner;
 55              RelativeTo  =  relativeTo;
 56              MoveCallback  =  moveCallback;
 57              BeforeDragCallback  =  beforeDragCallback;
 58              AfterDragCallback  =  afterDragCallback;
 59          }
 60 
 61           public   override   int  GetHashCode()
 62          {
 63               return  Owner.GetHashCode();
 64          }
 65 
 66           public   static   void  MoveOnCanvas(DraggableContext ctx)
 67          {
 68              Canvas cvs  =  ctx.RelativeTo  as  Canvas;
 69               if  (cvs  ==   null )  throw   new  NotSupportedException( " RelativeTo 必须是 Canvas " );
 70              ctx.Owner.SetValue(Canvas.TopProperty, ( double )(ctx.Owner.GetValue(Canvas.TopProperty))  +  ctx.Offset.X);
 71              ctx.Owner.SetValue(Canvas.LeftProperty, ( double )(ctx.Owner.GetValue(Canvas.LeftProperty))  +  ctx.Offset.Y);
 72          }
 73      }
 74 
 75       public   static   class  ClassHelper
 76      {
 77           private   static  Dictionary < Object, DraggableContext >  _dicDragContext  =   new  Dictionary < Object, DraggableContext > ();
 78 
 79           public   static   void  SetDraggable( this  UIElement element, IInputElement relativeTo, Action < DraggableContext >  moveCallback  =   null , Action < DraggableContext >  beforeDragCallback  =   null , Action < DraggableContext >  afterDragCallback  =   null )
 80          {
 81               if  (element  ==   null )  throw   new  ArgumentNullException( " element " );
 82 
 83              _dicDragContext[element]  =   new  DraggableContext(element, relativeTo, moveCallback, beforeDragCallback, afterDragCallback);
 84              element.MouseLeftButtonDown  +=   new  System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
 85              element.MouseLeftButtonUp  +=   new  System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
 86              element.MouseLeave  +=   new  System.Windows.Input.MouseEventHandler(element_MouseLeave);
 87              element.MouseMove  +=   new  System.Windows.Input.MouseEventHandler(element_MouseMove);
 88          }
 89 
 90           private   static   void  element_MouseLeftButtonUp( object  sender, System.Windows.Input.MouseButtonEventArgs e)
 91          {
 92              _dicDragContext[sender].Dragging  =   false ;
 93          }
 94 
 95           private   static   void  element_MouseLeftButtonDown( object  sender, System.Windows.Input.MouseButtonEventArgs e)
 96          {
 97              DraggableContext ctx  =  _dicDragContext[sender];
 98              ctx.Dragging  =   true ;
 99              ctx.StartPoint  =  e.GetPosition(ctx.RelativeTo);
100              ctx.EndPoint  =  ctx.StartPoint;
101          }
102 
103           private   static   void  element_MouseLeave( object  sender, System.Windows.Input.MouseEventArgs e)
104          {
105              _dicDragContext[sender].Dragging  =   false ;
106          }
107 
108           private   static   void  element_MouseMove( object  sender, System.Windows.Input.MouseEventArgs e)
109          {
110              DraggableContext ctx  =  _dicDragContext[sender];
111               if  (ctx.Dragging  ==   true )
112              {
113                  ctx.Dragging  =   true ;
114                  ctx.EndPoint  =  e.GetPosition(ctx.RelativeTo);
115                   if  (ctx.MoveCallback  !=   null )
116                  {
117                      ctx.MoveCallback(ctx);
118                  }
119                  ctx.StartPoint  =  ctx.EndPoint;
120              }
121          }
122 
123           public   static   void  UnsetDraggable( this  UIElement element)
124          {
125              element.MouseLeftButtonDown  -=   new  System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
126              element.MouseLeftButtonUp  -=   new  System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
127              element.MouseLeave  -=   new  System.Windows.Input.MouseEventHandler(element_MouseLeave);
128              element.MouseMove  -=   new  System.Windows.Input.MouseEventHandler(element_MouseMove);
129 
130               if  (_dicDragContext.ContainsKey(element)) _dicDragContext.Remove(element);
131          }
132      }
133  }
134 

====

下面,通过两个案例,看一下这样的封装能带来什么好处。

案例1:在一个ScrollViewer[scroll]中有1副Image[imgMain],当这个图像过大时,需要支持拖动,拖动时,鼠标由箭头变成手的样子,拖动完毕再变回来。界面见下图:

代码如下:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    this.imgMain.SetDraggable(this, this.Scroll, UseHandCursor, UseArrowCursor);
}

private void UseHandCursor(DraggableContext ctx)
{
    (ctx.Owner as FrameworkElement).Cursor = Cursors.Hand;
}

private void UseArrowCursor(DraggableContext ctx)
{
    (ctx.Owner as FrameworkElement).Cursor = Cursors.Arrow;
}

private void Scroll(DraggableContext ctx)
{
    this.scroll.ScrollToHorizontalOffset(this.scroll.HorizontalOffset - ctx.Offset.X);
    this.scroll.ScrollToVerticalOffset(this.scroll.VerticalOffset - ctx.Offset.Y);
}

如果使用 Lambda 表达式,则更简单。

案例2:还是和上面类似场景,在一个Canvas[cvsFont]上有很多文字(TextBlock[tb]),有的文字压着线了,需要手动拖好。当选中文字时,文字显示红色,拖动完毕,变成黑色。

相关代码为:

tb.SetDraggable(this.cvsFont,
                    (DraggableContext ctx) =>
                        {
                            FontContext pos = tb.DataContext as FontContext;
                            pos.X += ctx.Offset.X / ImageScale;
                            pos.Y += ctx.Offset.Y / ImageScale;
                            tb.SetValue(Canvas.TopProperty, pos.Y * ImageScale);
                            tb.SetValue(Canvas.LeftProperty, pos.X * ImageScale);
                        },
                    (DraggableContext ctx) =>
                        {
                            tb.Foreground = new SolidColorBrush(Colors.Red);
                        },
                    (DraggableContext ctx) =>
                        {
                            tb.Foreground = new SolidColorBrush(Colors.Black);
                        }
                    );

FontContext 存储了当缩放比为1时,tb 相对 cvsFont 的位置。这些TextBlock的生命周期比较短,它们排队领盒饭时,需要Unset一下:

tb.UnsetDraggable();

====

可以将常用的场景封装成方法,比如说,在DraggableContext类中添加下面的回调方法,将元素在Canvas上移动的逻辑抽象出来:

public static void MoveOnCanvas(DraggableContext ctx)
{
    Canvas cvs = ctx.RelativeTo as Canvas;
    if (cvs == null) throw new NotSupportedException("RelativeTo 必须是 Canvas");
    ctx.Owner.SetValue(Canvas.TopProperty, (double)(ctx.Owner.GetValue(Canvas.TopProperty)) + ctx.Offset.X);
    ctx.Owner.SetValue(Canvas.LeftProperty, (double)(ctx.Owner.GetValue(Canvas.LeftProperty)) + ctx.Offset.Y);
}

如果一个元素放置在Canvas上,且只需要支持拖动,不需要其它的逻辑,则一句话就搞定了:

xxx.SetDraggable(cvsXXX,DraggableContext.MoveOnCanvas);

====

2010年11月13日对代码进行修改,修改后的代码更简洁,使用更简单,不用手动Unset,且可以挂接多个逻辑。

代码如下:

代码

  1  using  System;
  2  using  System.Collections.Generic;
  3  using  System.Linq;
  4  using  System.Text;
  5  using  System.Windows;
  6  using  System.Windows.Controls;
  7 
  8  namespace  Orc.Util
  9  {
 10       public   class  DraggableContext
 11      {
 12           public  DependencyObject Owner {  get ;  private   set ; }
 13           public  IInputElement RelativeTo {  get ;  private   set ; }
 14           public  Point StartPoint {  get ;  internal   set ; }
 15           public  Point EndPoint {  get ;  internal   set ; }
 16 
 17           public  Point Offset
 18          {
 19               get  {  return   new  Point { X  =  EndPoint.X  -  StartPoint.X, Y  =  EndPoint.Y  -  StartPoint.Y }; }
 20          }
 21 
 22           private  Boolean _dragging;
 23 
 24           public  Boolean Dragging
 25          {
 26               get  {  return  _dragging; }
 27               internal   set
 28              {
 29                   if  (value  !=  _dragging)
 30                  {
 31                      _dragging  =  value;
 32                       if  (value  ==   true )
 33                      {
 34                           if  (BeforeDragCallback  !=   null )
 35                              BeforeDragCallback( this );
 36                      }
 37                       else
 38                      {
 39                           if  (AfterDragCallback  !=   null )
 40                              AfterDragCallback( this );
 41                      }
 42                  }
 43              }
 44          }
 45 
 46           internal   void  element_MouseLeftButtonUp( object  sender, System.Windows.Input.MouseButtonEventArgs e)
 47          {
 48               this .Dragging  =   false ;
 49          }
 50 
 51           internal   void  element_MouseLeftButtonDown( object  sender, System.Windows.Input.MouseButtonEventArgs e)
 52          {
 53               this .Dragging  =   true ;
 54               this .StartPoint  =  e.GetPosition( this .RelativeTo);
 55               this .EndPoint  =   this .StartPoint;
 56          }
 57 
 58           internal   void  element_MouseLeave( object  sender, System.Windows.Input.MouseEventArgs e)
 59          {
 60               this .Dragging  =   false ;
 61          }
 62 
 63           internal   void  element_MouseMove( object  sender, System.Windows.Input.MouseEventArgs e)
 64          {
 65               if  ( this .Dragging  ==   true )
 66              {
 67                   this .Dragging  =   true ;
 68                   this .EndPoint  =  e.GetPosition( this .RelativeTo);
 69                   if  ( this .MoveCallback  !=   null )
 70                  {
 71                       this .MoveCallback( this );
 72                  }
 73                   this .StartPoint  =   this .EndPoint;
 74              }
 75          }
 76 
 77           public  Action < DraggableContext >  MoveCallback {  get ;  private   set ; }
 78 
 79           public  Action < DraggableContext >  BeforeDragCallback {  get ;  private   set ; }
 80 
 81           public  Action < DraggableContext >  AfterDragCallback {  get ;  private   set ; }
 82 
 83           public  DraggableContext(DependencyObject owner, IInputElement relativeTo, Action < DraggableContext >  moveCallback  =   null , Action < DraggableContext >  beforeDragCallback  =   null , Action < DraggableContext >  afterDragCallback  =   null )
 84          {
 85              Owner  =  owner;
 86              RelativeTo  =  relativeTo;
 87              MoveCallback  =  moveCallback;
 88              BeforeDragCallback  =  beforeDragCallback;
 89              AfterDragCallback  =  afterDragCallback;
 90          }
 91 
 92           public   override   int  GetHashCode()
 93          {
 94               return  Owner.GetHashCode();
 95          }
 96 
 97           public   static   void  MoveOnCanvas(DraggableContext ctx)
 98          {
 99              Canvas cvs  =  ctx.RelativeTo  as  Canvas;
100               if  (cvs  ==   null )  throw   new  NotSupportedException( " RelativeTo 必须是 Canvas " );
101              ctx.Owner.SetValue(Canvas.TopProperty, ( double )(ctx.Owner.GetValue(Canvas.TopProperty))  +  ctx.Offset.X);
102              ctx.Owner.SetValue(Canvas.LeftProperty, ( double )(ctx.Owner.GetValue(Canvas.LeftProperty))  +  ctx.Offset.Y);
103          }
104      }
105 
106       public   static   class  ClassHelper
107      {
108           public   static   void  SetDraggable( this  UIElement element, IInputElement relativeTo, Action < DraggableContext >  moveCallback  =   null , Action < DraggableContext >  beforeDragCallback  =   null , Action < DraggableContext >  afterDragCallback  =   null )
109          {
110               if  (element  ==   null )  throw   new  ArgumentNullException( " element " );
111              DraggableContext ctx  =   new  DraggableContext(element, relativeTo, moveCallback, beforeDragCallback, afterDragCallback);
112              element.MouseLeftButtonDown  +=   new  System.Windows.Input.MouseButtonEventHandler(ctx.element_MouseLeftButtonDown);
113              element.MouseLeftButtonUp  +=   new  System.Windows.Input.MouseButtonEventHandler(ctx.element_MouseLeftButtonUp);
114              element.MouseLeave  +=   new  System.Windows.Input.MouseEventHandler(ctx.element_MouseLeave);
115              element.MouseMove  +=   new  System.Windows.Input.MouseEventHandler(ctx.element_MouseMove);
116          }
117      }
118  }

转载于:https://www.cnblogs.com/xiaotie/archive/2010/11/10/1874054.html

使用扩展方法对代码的行为进行封装的例子:封装UIElement的“拖动”相关推荐

  1. appsetting mysql_给IConfiguration写一个GetAppSetting扩展方法(示例代码)

    给 IConfiguration 写一个 GetAppSetting 扩展方法 Intro 在 .net core 中,微软已经默认使用 appsettings.json 来代替 app.config ...

  2. 用 .NET 3.5 创建 ToJSON() 扩展方法

    今年早些时候,我通过blog介绍了 C# 和 VB 语言的一项新的扩充特性"扩展方法". 扩展方法让开发者可以向已有的 CLR 类型的公共契约中添加新的方法,而不需要子类化或重新编 ...

  3. c#扩展方法奇思妙用性能篇一:扩展方法性能初测

    最近写了几篇<c#扩展方法奇思妙用>的文章,一直只是讨论如何扩展.如何使用的问题,几乎没有涉及效率方面. 而大家的回复好多都在问效率如何.性能怎样,也引起了我对效率的关注,今天将初步测试的 ...

  4. .NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

    开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以, ...

  5. 技巧/诀窍:用 .NET 3.5 创建 ToJSON() 扩展方法 (木野狐译)

    [原文地址] Tip/Trick: Building a ToJSON() Extension Method using .NET 3.5 [原文发表日期] Monday, October 01, 2 ...

  6. 用 .NET 3.5 创建 ToJSON() 扩展方法 (木野狐译)

    [原文地址] Tip/Trick: Building a ToJSON() Extension Method using .NET 3.5  [原文发表日期] Monday, October 01, ...

  7. Kotlin扩展方法进化之Context Receiver

    /   今日科技快讯   / 近日,福特汽车公司宣布将削减总计3000个受薪和合同工职位,被裁员目标主要位于北美和印度.此举表明,该公司正在进行重组,以在开发软件驱动的电动汽车领域追赶特斯拉. /  ...

  8. MongoDB:利用官方驱动改装为EF代码风格的MongoDB.Repository框架 五 --- 为ListMongoDBRef增加扩展方法...

    本次改动主要内容:为List<MongoDBRef>增加扩展方法 在MongoDB.Repository的使用过程中,发现在一个类中只定义一个List<MongoDBRef>是 ...

  9. 【Groovy】Groovy 扩展方法 ( 扩展静态方法示例 | 扩展实例方法示例 | 扩展实例方法与扩展静态方法代码相同 )

    文章目录 一.扩展静态方法示例 二.扩展实例方法示例 三.扩展实例方法与扩展静态方法代码相同 一.扩展静态方法示例 在上一篇博客 [Groovy]Groovy 扩展方法 ( Groovy 扩展方法引入 ...

最新文章

  1. 用Groovy思考 第一章 用Groovy简化Java代码
  2. python必刷面试_Python面试必刷题系列(5)
  3. MVC命名空间中的~UrlHelper中的Action方法告诉我们方法重载的重要性(路由的统一)...
  4. VOC2007xml转YOLO的txt格式代码
  5. SpringMVC自学日志03(SpringMVC注解)
  6. Ubuntu开启或重启ssh服务
  7. OpenGL基础54:点光源阴影
  8. JS取得RadioButtonList的Value,Text及选中值等信息
  9. 2019开放大学计算机应用基础,国家开放大学2019年电大计算机应用基础考试试题一试卷(国家开放大学).doc...
  10. matlab imagesc 平滑,在matlab中,如何使用imagesc在2D热图中“平滑”像素
  11. 科学计算机恢复初始化,快速解决Windows 10系统还原一直初始化或卡住的方法!...
  12. Teamviewer远程,应用界面显示空白
  13. 微信公众号(订阅号)申请流程
  14. 怎么用计算机算分数加减法,怎么算分数加减法?怎么教给孩子?
  15. Vue3.0项目——打造企业级音乐App(二)图片懒加载、v-loading指令的开发和优化
  16. CRM学习笔记类转换工具(pojo互转)上下文中获取用户名cookie工具
  17. EtherCAT之Lan9252调试笔记
  18. 皮卡智能2022年功能升级汇总,打造智能工作新体验
  19. java线程中的tid_jstack中的tid到底是什么意思呢
  20. 半年亏损超5亿美元/股价腰斩,这家自动驾驶公司日子不好过

热门文章

  1. 补充微量元素钙会使身体更强健
  2. OpenCV之Mat的详细介绍
  3. 自己开发前端调试工具:Gungnir
  4. Flash as3嵌入中文字体的方法
  5. 26个字母贴切表达80后的个性
  6. 一、音频基础知识 - dB/dBSPL/dBFS关系
  7. 大数据开发步骤和流程
  8. mysql-generator用法_mybatis-generator使用教程
  9. 基础理论之永磁同步电机
  10. 解决:413错误码 Payload Too Large