2021年3月31日星期三

沃尔玛对非美国供应商开放入驻,会威胁到亚马逊吗?

最近的沃尔玛一直有频繁的举动,您或许已经留意到,沃尔玛在电子商务领域的势头愈发强劲,并正在成为亚马逊最大竞争对手之一。

在大流行之前,这两家巨头企业分别专注于不同领域--亚马逊的线上平台和沃尔玛的实体店。而在大流行之际,后者已逐渐作出改变,以适应不断增长的在线购物需求。

近期,沃尔玛宣布取消其仅在美国注册的供应商的要求,允许非美国供应商进入其市场,被外界视为与亚马逊竞争并引入海外商家的举措。

不久之后,买家可能会在沃尔玛上看到更多的外国商家,也很有可能绝大部分不来自中国。目前,在亚马逊上,中国卖家占据了BSR商品的近60%,随着沃尔玛对海外供应商的开放,极有可能会有类似的结果。

中国卖家申请流程:

卖家需要在平台上提交销售申请,平台进行审核和批准。目前的申请过程需要花费数周的时间,如果获得批准,卖家将收到沃尔玛的出售邀请。

图片1.png

中国卖家进去沃尔玛需要准备什么?

与亚马逊相比,沃尔玛的审核程序更为严格,中国卖家需要满足以下三点要求:

有效的中国营业执照

在北美市场有超过一年的销售经验

良好的店铺评价

在2020年,尽管亚马逊发展越来越大,但沃尔玛在收入和利润上都更胜一筹

图片2.png

2020年的2月份,沃尔玛还推出了沃尔玛配送服务(WFS),与亚马逊的亚马逊物流(FBA)一样,该服务允许第三方卖家为存储,包装和运输产品付款。WFS保证为期两天的交付期和一个简单的成本结构,其中包括以下内容:固定的每月存储费,基于运输重量的履行价格。

此外,沃尔玛的Express Delivery服务,号称可以在两小时或更短的时间内送达客户的门口。Express Delivery服务将在现有交付费用之上额外收取10美元。但是,如果您是该公司的Delivery Unlimited订阅服务的成员,则只需为每个Express Delivery支付10美元的费用。由于它是相当新的,因此客户必须检查其所在区域是否可用。

过去最低订购要求为35美元,但沃尔玛最近宣布将取消这一要求。相比沃尔玛Prime的119美元,加入沃尔玛+的会员每年的费用也更便宜,为98美元。

沃尔玛在电子商务的路上还需要做大量的工作,但是,在此过程中,并没有放慢脚步,在未来几年,能否超越亚马逊,还值得期待。



原创:跨境知道 晓阳


文章来源:https://www.ikjzd.com/home/143668

跨境电商:https://www.ikjzd.com/

e邮包:https://www.ikjzd.com/w/594.html?source=tagwish

淘粉吧返利:https://www.ikjzd.com/w/1725

萌店:https://www.ikjzd.com/w/1538

沃尔玛对非美国供应商开放入驻,会威胁到亚马逊吗?

最近的沃尔玛一直有频繁的举动,您或许已经留意到,沃尔玛在电子商务领域的势头愈发强劲,并正在成为亚马逊最大竞争对手之一。 在大流行之前,这两家巨头企业分别专注于不同领域--亚马逊的线上平台和沃尔玛的实体店。而在大流行之际,后者已逐渐作出改变,以适应不断增长的在线购物需求。

汉密尔顿回应质疑:喷我“只能靠车取胜”的人们都错了_比赛

原标题:汉密尔顿回应质疑:喷我"只能靠车取胜"的人们都错了

上周日,汉密尔顿在新赛季揭幕战巴林大奖赛中,最后阶段顶住巨大压力率先冲线赢得开门红。在拿下个人第96个分站冠军后,汉密尔顿表示:希望这场胜利能够让那些此前认为他只是依靠梅奔车好才能获胜的人们知道他们是错的。

在巴林,驾驶红牛RB16B的小维斯塔潘从季前测试、自由练习赛、排位赛都证明他们的赛车在速度上要比梅赛德斯W12更快。但周日正赛,汉密尔顿取得了一场漂亮的胜利,尤其是最后几圈抵挡住了数次向他发起攻击的维斯塔潘。此前,对于汉密尔顿和他在这项运动中所取得成功总有一种批评的声音,"他只能在梅赛德斯赛车中获胜"。

鉴于红牛在巴林的速度优势,汉密尔顿再次证明了他不需要最快的赛车同样能够在F1比赛中取得胜利—实际上,去年在土耳其的比赛他就证明了这一点。汉密尔顿说道:"我认为这场比赛绝对是一种变相的祝福,我认为总有机会证明(此前认为我只能依靠梅赛德斯赛车快才能赢得比赛的)人们是错误的,我想今天绝对是其中之一。但是我认为过去也有很多次,我加盟梅奔已经很长一段时间了,我希望将来有更多机会可以展示我在上周末比赛时的能力。"

"当然我们很幸运,维斯塔潘在4号弯走大了,但我很确定不会再发生这样的事情了,所以我们必须做得更好,变得更聪明,事实上我们的赛车目前还不是最快的,但这就是我的全部。我不介意为了改变现状而必须付出额外的努力。"

F1总经理罗斯-布朗在赛后的专栏中对汉密尔顿大加赞赏,称他在巴林的驾驶是"他职业生涯中最好的比赛之一。这是一场令人激动的比赛,但在汉密尔顿完成了一次令人兴奋,并且堪称他职业生涯表现最好的一战后,他理应获得这一荣誉。"

"他开得非常出色,轮胎节奏也很好,尽管不是全场最快的赛车,但在整场比赛中都极具威胁。有那么一两个瞬间,他在小维斯塔潘的压力下蹒跚而行,但每次他都坚持不懈,以令人印象深刻的方式站稳脚跟!"(陶朗加)返回搜狐,查看更多

责任编辑:

原文转载:http://sport.shaoqun.com/a/512746.html

跨境电商:https://www.ikjzd.com/

上海跨境通:https://www.ikjzd.com/w/1329

review:https://www.ikjzd.com/w/2735


原标题:汉密尔顿回应质疑:喷我"只能靠车取胜"的人们都错了上周日,汉密尔顿在新赛季揭幕战巴林大奖赛中,最后阶段顶住巨大压力率先冲线赢得开门红。在拿下个人第96个分站冠军后,汉密尔顿表示:希望这场胜利能够让那些此前认为他只是依靠梅奔车好才能获胜的人们知道他们是错的。在巴林,驾驶红牛RB16B的小维斯塔潘从季前测试、自由练习赛、排位赛都证明他们的赛车在速度上要比梅赛德斯W12更快。但周日正赛,汉密尔顿
modcloth:https://www.ikjzd.com/w/1271
beien:https://www.ikjzd.com/w/1336
xinong:https://www.ikjzd.com/w/1368
尴尬 网友直勾勾盯着我的酥胸:http://www.30bags.com/a/252066.html
口述:目睹哥们调戏我 老公在旁边傻笑:http://lady.shaoqun.com/m/a/19518.html
微博粉丝突破1200万,蔡徐坤送福利,粉丝:非常期待了:http://yl.shaoqun.com/a/104450.html

HashMap底层原理分析

本文将从以下方面结合源码进行分析:自动扩容、初始化与懒加载、哈希计算、位运算与并发,(默认采用JDK1.8)。
 
自动扩容
扩容操作发生在putVal最后部分,在增加元素后才判断是否需要扩容,如果超过阈值,会自动扩容。

 
 
 
 
 
 
 
 
 
 
这里扩容都是<<1翻倍进行扩容的。

扩容时节点数组进行数据转移的三种情况:
  • 节点的元素无后继节点:

  直接根据节点hash值重新计算下标,然后复制到新的数组中。

  • 节点为树节点:

  进行红黑树的扩容操作。

  因为capacity变化后,hash&(cap-1)可能得到不同结果。原有的红黑树变成高低位两个红黑树。低位红黑树下标位置和旧数组相同,高位红黑树下标位置在旧数组的基础上+oldCap,因为hash&(2*cap-1)结果等于hash&(cap-1)或者hash&(cap-1)+cap。

   红黑树扩容时遍历原有链表,然后根据新的hash值重新分为低位链表和高位链表。
  若所有元素都在低位链表或高位链表,则不需要重新树化,直接将链表头节点插入数组对应位置;
  若低位链表或高位链表的数量<7,则深拷贝低位或高位树节点链表得到普通节点新链表(低位或高位树节点链表含有树的偏序关系,拷贝得到的普通节点链表只有链表的偏序关系),并将新链表头节点插入数组对应位置。
  具体源码分析如下:


 1 final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) { 2  // 获取自身树节点 3  TreeNode<K,V> b = this; 4  // Relink into lo and hi lists, preserving order 5  // 低位链表的头尾节点 6  TreeNode<K,V> loHead = null, loTail = null; 7  // 高位链表的头尾节点 8  TreeNode<K,V> hiHead = null, hiTail = null; 9  // 低位链表节点数量、高位链表节点数量10  int lc = 0, hc = 0;11  for (TreeNode<K,V> e = b, next; e != null; e = next) {12   next = (TreeNode<K,V>)e.next;13   // 这步操作不是多余的,在e为低位或高位链表最终尾节点时起到赋空作用14   e.next = null;15   // 如果仍然在原位置,则加入低位链表16   if ((e.hash & bit) == 0) {17    if ((e.prev = loTail) == null)18     loHead = e;19    else20     loTail.next = e;21    loTail = e;22    ++lc;//低位链表数量+123   }24   else {25    // 如果是在新的位置(原索引值+oldcap),加入高位链表26    if ((e.prev = hiTail) == null)27     hiHead = e;28    else29     hiTail.next = e;30    hiTail = e;31    ++hc;// 高位链表数量+132   }33  }34  // 低位链表不为空35  if (loHead != null) {36   // 低位链表数量不超过6,则深拷贝低位树节点链表得到普通节点新链表,并将新链表头部放入数组37   if (lc <= UNTREEIFY_THRESHOLD)38    tab[index] = loHead.untreeify(map);39   else {40    tab[index] = loHead;41    // 如果高位链表为空,说明全部元素都在低位链表中,因为原链表已经是树化的了,所以不用再转为红黑树42    if (hiHead != null) // (else is already treeified)43     loHead.treeify(tab);44   }45  }46  // 高位链表不为空47  if (hiHead != null) {48   // 高位链表数量不超过6,则深拷贝树节点高位链表得到普通节点新链表,并将新链表头部放入数组49   if (hc <= UNTREEIFY_THRESHOLD)50    tab[index + bit] = hiHead.untreeify(map);51   else {52    tab[index + bit] = hiHead;53    // 如果低位链表为空,说明全部元素都在高位链表中,因为原链表已经是树化的了,所以不用再转为红黑树54    if (loHead != null)55     hiHead.treeify(tab);56   }57  }58 }

 

  • 节点为链表节点:

  进行链表的复制操作。操作和红黑树扩容操作非常相似。也是先遍历原有链表节点,然后根据新的hash值分为低位链表和高位链表。
  分完高低位链表后,将头节点插入数组对应位置即可。
  具体源码分析如下:
 1 // case3:节点为链表节点,进行链表的赋值操作  2 else { // preserve order 3  // 低位Node链表头节点和尾节点 4  Node<K,V> loHead = null, loTail = null; 5  // 高位Node链表头节点和尾节点 6  Node<K,V> hiHead = null, hiTail = null; 7  Node<K,V> next; 8  // 遍历原链表,拆分成低位链表和高位链表 9  do {10   next = e.next;11   // 如果是在原位置,则加入低位链表12   if ((e.hash & oldCap) == 0) {13    if (loTail == null)14     loHead = e;15    else16     loTail.next = e;17    loTail = e;18   }19   else {20    // 如果不在原位置,加入高位链表21    if (hiTail == null)22     hiHead = e;23    else24     hiTail.next = e;25    hiTail = e;26   }27  } while ((e = next) != null);28  // 如果低位链表不为空29  if (loTail != null) {30   // 尾部节点赋空并将头部节点放入数组指定位置31   loTail.next = null;32   newTab[j] = loHead;33  }34  // 如果高位链表不为空35  if (hiTail != null) {36   // 尾部节点赋空并将头部节点放入数组指定位置37   hiTail.next = null;38   newTab[j + oldCap] = hiHead;39  }40 }

 在jdk1.8之前,hashmap在多线程环境中使用会出现死链问题。如果有多个线程同时进行扩容操作,一个线程拿到链表头节点和后继节点时挂起,另一个线程执行完扩容操作,会使得这两个节点互相依赖,出现死链,导致第一个线程不能退出循环,CPU使用率飙升。

jdk1.8将原来的头插法改为了尾插法,同时复制链表时不再是遍历一个节点就插入,而是使用高低位链表。待遍历完所有节点后,再将高低位链表放入新数组对应位置。

但是仍然不建议在多线程环境下使用,仍然会有数据缺失和数据重复等等问题。



 















原文转载:http://www.shaoqun.com/a/654745.html

跨境电商:https://www.ikjzd.com/

心怡:https://www.ikjzd.com/w/1327

笨鸟海淘:https://www.ikjzd.com/w/1550


本文将从以下方面结合源码进行分析:自动扩容、初始化与懒加载、哈希计算、位运算与并发,(默认采用JDK1.8)。自动扩容扩容操作发生在putVal最后部分,在增加元素后才判断是否需要扩容,如果超过阈值,会自动扩容。这里扩容都是<<1翻倍进行扩容的。扩容时节点数组进行数据转移的三种情况:节点的元素无后继节点:  直接根据节点hash值重新计算下标,然后复制到新的数组中。节点为树节点:  进
mav:https://www.ikjzd.com/w/2414
c2c:https://www.ikjzd.com/w/1576
6pm:https://www.ikjzd.com/w/317
"杀虫剂"错杀风又来?卖家赶紧防备起来!:https://www.ikjzd.com/home/105201
两女双飞,,,用力_女人口述二女伺候一男做:http://www.30bags.com/m/a/254325.html
我和学妹在图书馆里做:口述图书馆里初夜激情后:http://lady.shaoqun.com/m/a/273518.html

2021年3月30日星期二

WPF之动画

XAML绘图本身就是矢量的,支持各式各样的填充和效果,还可以添加滤镜。XAML矢量图是借助Microsoft Expression Studio中的Design和Blend两个工具画出来的。动画本质就是在一个时间段内对象位置、角度、颜色、透明度等属性值的连续变化,有些是对象自身的属性,有些则是图形变形的属性。变化即是运动,WPF的动画也是一种运动,运动的主体就是各种UI元素,运动本身就是施加在UI元素上的一些Timeline派生类的实例。

目录
  • WPF绘图
    • 直线(Line)
    • 矩形(Rectangle)
    • 椭圆(Ellipse)
    • 路径(Path)
    • 路径标记语法
    • 使用Path剪裁界面元素
  • 图形的效果与滤镜
    • 简单易用的BitmapEffect
    • 丰富多彩的Effect
  • 图形的变形
    • 呈现变形
    • 布局变形
  • 动画
    • 简单独立动画
      • 简单线性动画
      • 高级动画控制
      • 关键帧动画
      • 特殊的关键帧
      • 路径动画
    • 场景


WPF在动画和3D上的优势主要有:

  • XAML语言针对的是界面美化问题,可以让设计师直接加入开发团队、降低沟通成本。
  • XAML的图形绘制功能非常强大,可以轻易绘制出复杂的图标、图画。
  • WPF支持"滤镜"功能,可以像Photoshop那样为对象添加各种效果。
  • WPF原生支持动面开发,设计师、程序员都能够使用XAML或C#轻松开发制作出炫丽的动画效果。
  • WWF原生支持3D效果,甚至可以将其他3D建模工具创建的模型导入进来使用。
  • Blend作为专门的设计工具让WPF如虎添翼,既能帮助不了解编程的设计师快速上手,又能帮助资深开发者快速建立图形或动画的原型。

WPF绘图

XAML绘图本身就是矢量的,支持各式各样的填充和效果,还可以添加滤镜。

XAML矢量图是借助Microsoft Expression Studio中的Design和Blend两个工具画出来的。Blend可以直接绘制XAML图形;Design可以像Photoshop或者Fireworks那样绘制图形,再由设计者决定导出为PNG或XAML格式。

这些图片都是由有限的几个基本图形组成的,WPF的基本图形包括以下几个(它们都是Shape类的派生类):

  • Line:直线段,可以设置其笔触(Stroke)。
  • Rectangle:矩形,既有笔触,又有填充(Fill)。
  • Ellipse:椭圆,长、宽相等的椭圆即为正圆,既有笔触又有填充。
  • Polygon:多边形,由多条直线段围成的闭合区域,既有笔触又有填充。
  • Polyline:折线(不闭合),由多条首尾相接的直线段组成。
  • Path:路径(闭合区域),基本图形中功能最强大的一个,可由若干直线、圆弧、贝塞尔曲线组成。

直线(Line)

直线是最简单的图形,使用X1、Y1两个属性可以设置它的起点坐标,X2、Y2两个属性则用来设置其终点坐标,控制起点/终点坐标就可以实现平行、交错等效果,一些属性还能控制画出虚线以及控制线段终点的形状。

Stroke(笔触)属性的数据类型是Brush(画刷),凡是Brush的派生类均可用于给这个属性赋值。

WPF提供了多种渐变色画刷,画直线也可以画出渐变效果,下面的例子综合了这些属性:

<Window x:  

效果如下:

注:绘图可以在任何一种布局控件中完成,WPF会自动根据容器的不同计算图形的坐标,常用的绘图容器是Canvas和Grid

矩形(Rectangle)

矩形由笔触(Stroke,即边线)和填充(Fill)构成。Stroke属性的设置与Line一样,Fill属性的数据类型是Brush。

Brush是个抽象类,只能用Brush派生类的实例为Fill属性赋值,常用的Brush类型有:

  • SolidColorBrush:实心画刷,在XAML中可以使用颜色名称字符串(如Red、Blue)直接赋值。
  • LinearGradientBrush:线性渐变画刷,色彩沿设定的直线方向、按设定的变化点进行渐变。
  • RadialGradientBrush:径向渐变画刷,色彩沿半径的方向、按设定的变化点进行渐变,形成圆形填充。
  • ImageBrush:使用图片(Image)作为填充内容。
  • DrawingBrush:使用矢量图(Vector)和位图(Bitmap)作为填充内容。
  • VisualBrush:每个控件的可视化形象可以通过Visual类的方法获得(Visual->FrameworkElement),获得可视化的形象后可以用VisualBrush这个形象进行填充,如拖拽控件时鼠标松开前的控件"幻影"

下面是使用各种画刷填充矩形的综合实例:

<Window x:  

效果如下:

在使用画刷的时候,建议先在Blend里绘制出大致效果然后再在Visual Studio里进行微调。

接下来看一个VisualBrush的例子,目标控件是一个Button,程序的XAML代码如下:

<Window x:  

中间Button的Click事件处理器代码如下:

double o = 1.0;//不透明度计数器private void CloneVisual(object sender, RoutedEventArgs e){ VisualBrush vBrush = new VisualBrush(this.realButton); Rectangle rect = new Rectangle();  rect.Width = realButton.ActualWidth;  rect.Height = realButton.ActualHeight; rect.Fill = vBrush; rect.Opacity = o; o -= 0.2;  this.stackPanelRight.Children.Add(rect);}

效果如下:

椭圆(Ellipse)

椭圆也是一种常用的几何图形,使用方法与矩形没有什么区别。

绘制一个球体,球体的轮廓是正圆(Circle),Width与Height相等的椭圆即是正圆;球体的光影效果使用径向渐变实现。XAML代码如下:

<Window x:  

效果如下:

椭圆的绘制和色彩填充都是在Blend里完成的,在Visual Studio里又进行了一些调整(包括规整数值、调整顺序和去掉无用代码)。

路径(Path)

路径(Path)完全可以替代其他几种图形,可以将直线、圆弧、贝塞尔曲线等基本元素结合进来,形成更复杂的图形。
路径最重要的一个属性是Data,Data的数据类型是Geometry(几何图形),使用这个属性将一些基本的线段拼接起来、形成复杂的图形,赋值的语法有两种:

  • 标签式的标准语法
  • 专门用于绘制几何图形的"路径标记语法"

本小节借助标准语法认识各种基本线段,下一小节将学习绘制几何图形的路径标记语法。

Path的Data属性是Geometry类(抽象类,不可直接使用),可以使用的是Geometry的子类,Geometry的子类包括:

  • LineGeometry:直线几何图形。
  • RectangleGeometry:矩形几何图形。
  • EllipseGeometry:椭圆几何图形。
  • PathGeometry:路径几何图形。
  • StreamGeometry:PathGeometry的轻量级替代品,不支持Binding、动画等功能。
  • CombinedGeometry:由多个基本几何图形联合在一起,形成的单一几何图形。
  • GeometryGroup:由多个基本几何图形组合在一起,形成的几何图形组。

区别在于前面介绍的Line、Rectangle、Ellipse类都是可以独立存在的对象,这些*Geometry类只能用于结合成其他几何图形、不能独立存在

当在Blend里选中一组独立的几何图形并在菜单里执行组合路径的命令时,本质上就是把原来独立的Line、Rectangle、Ellipse对象转换成*Geometry对象并结合成一个新的复杂几何图形。

下面例子是简要展示各个几何图形:

<Window x:  

效果如下:

WPF绘图的重点在于Path,Path的重点在于PathGeometry。PathGeometry的Figures属性可以容纳PathFigure对象,而PathFigure的Segments属性又可以容纳各种线段用于结合成复杂图形,XAML代码结构如下:

<Path> <Path.Data>  <PathGeometry>   <PathGeometry.Figures>    <PathFigure>     <PathFigure.Segments>      <!--各种线段-->     </PathFigure.Segments>    </PathFigure>   </PathGeometry.Figures>  </PathGeometry> </Path.Data></Path>

Figures是PathGeometry的默认内容属性、Segments是PathFigure的默认内容属性,常简化为这样:

<Path> <Path.Data>  <PathGeometry>        <PathFigure>           <!--各种线段-->          </PathFigure>       </PathGeometry> </Path.Data></Path>

上面格式中的各种线段是:

  • LineSegment:直线段。
  • ArcSegment:圆弧线段。
  • BezierSegment:三次方贝塞尔曲线段(默认贝塞尔曲线就是指三次曲线,所以Cubic一词被省略)。
  • QuadraticBezierSegment:二次方贝塞尔曲线段。
  • PolyLineSegment:多直线段。
  • PolyBezierSegment:多三次方贝塞尔曲线段。
  • PolyQuadraticBezierSegment:多二次方贝塞尔曲线。

注:所有这些线段都没有起点(StartPoint),起点就是前一个线段的终点,而第一个线段的起点则是PathFigure的StartPoint

LineSegment最为简单,只需要控制它的Point(终点)即可,XAML代码如下:

<Window x:  

效果如下:

ArcSegment用来绘制圆弧:

  • Point属性用来指明圆弧连接的终点;
  • Size属性是完整椭圆的横轴半径和纵轴半径(圆弧截取自椭圆);
  • SweepDirection属性指明圆弧是顺时针方向还是逆时针方向;
  • IsLargeArc属性用于指明是否使用大弧去连接(如果椭圆上的两点位置不对称,那么这两点间的圆弧就会分为大弧和小弧);
  • RotationAngle属性用来指明圆弧母椭圆的旋转角度。

几个属性的变化如下所示:

BezierSegment(三次方贝塞尔曲线)由4个点决定:

  • 起点:即前一个线段的终点或PathFigure的StartPoint。
  • 终点:Point3属性,即曲线的终点位置。
  • 两个控制点:Point1和Point2属性。
    三次方贝塞尔曲线就是由起点出发走向Pointl的方向,再走向Point2的方向,最后到达终点的平滑曲线,如下为XAML代码表示的三次方贝塞尔曲线:
<Window x:  

效果如下:

想绘制出复杂的图画来,要做的仅仅是在PathFigure把Segment一段一段加上去。
GeometryGroup也是Geometry的一个派生类,它最大的特点是可以将一组PathGeometry组合在一起,如下面的例子所示:

<Window x:  

效果如下:

路径标记语法

Path的一大缺点是其标签式语法的烦琐,复杂图形(Path)都是由数十条线段连接而成,按照标签式语法,每条线段(Segment)是一个标签、每个标签占据一行,一个图形就要占去几十行代码。

借助专供WPF绘图使用的路径标记语法(Path Markup Syntax)可以极大地简化Path的描述,路径标记语法实际上就是各种线段的简记法(可以简写为"L150,5"),还增加了一些更实用的绘图命令("H180"指从当前点画一条终点横坐标是180、纵坐标与当前点一致的水平直线)。

使用路径标记语法绘图时一般分三步:移动至起点一绘图→闭合图形,这三步使用的命令稍有差别:

  • 移动到起点使用的是"移动命令"M
  • 绘图使用的是绘图命令,包括L、H、V、A、C、Q等
  • 如果图形是闭合的,需要使用"闭合命令"Z,这样最后一条线段的终点与第一条线段的起点间会连接上一条直线段。

路径标记语法不区分大小写(A与a、H与h等价),使用两个double类型数值来表示一个点,第一个值表示横坐标(常记为x),第二个值表示纵坐标(常记为y),两个数值既可以使用逗号分隔(x,y)又可以使用空格分隔(x y)。
注:由于路径标记法语中使用空格作为两个点之间的分隔,为了避免混淆,建议使用逗号作为点横纵坐标的分隔符

常用路径标记语法的总结如下所示:

在上述命令中,S和T两个命令比较特殊:

  • S用于绘制平滑三次方贝塞尔曲线,只需要给出一个控制点(相当于普通三次方贝塞尔曲线的第二个控制点),平滑三次方贝塞尔曲线会把前一条三次方贝塞尔曲线的第二控制点以起点为对称中心的对称点当作自己的第一控制点(如果前面的线段不是三次方贝塞尔曲线,则第一控制点与起点相同)。
    下面两条曲线等价:
<Path Stroke="Red" Data="M 0,0 C30,0 70,100 100,100 S 170,0 200,0"/><Path Stroke="Black" Data="M 0,0 C30,0 70,100 100,100 C 130,100 170,0 200,0"/>
  • T命令用于绘制平滑二次方贝塞尔曲线,绘制的时候如果前面的线段也是一段二次方贝塞尔曲线的话,T命令会把前面这段曲线的控制点以起点为对称中心的对称点当作自己的控制点(如果前面的线段不是二次方贝塞尔曲线则控制点与起点相同)。
    下面两条曲线等价:
<Path Stroke="Red" Data="M 0,200 Q 100,0 200,200 T 400,200"/><Path Stroke="Black" Data="M 0,200 Q 100,0 200,200 Q 300,400 400,200"/>

使用方法是把这些命令串起来、形成一个字符串,然后赋值给Path的Data属性。使用Blend绘图时,Blend会自动使用路径标记语法来记录数据而不是使用代码量巨大的标签式语法。

使用Path剪裁界面元素

遇到制作不规则窗体或控件的需求,仅需使用窗体或控件的Clip属性就可以轻松做到。Clip属性被定义在UIElement类中,WPF窗体和所有控件、图形都具有这个属性。

Clip属性的数据类型是Geometry(与Path的Data属性一致),只要按需求制作好特殊形状的Path并把Path的Data属性值赋给目标窗体、控件或其他图形,对目标的剪切就完成了。

请看下面这个不规则窗体的例子(数据经过优化):

<Window x:  

注:想让一个窗体能够被剪切,其AllowsTransparency必须设为True,WindowStyle属性必须设为None
窗体中Buton的Click事件处理器如下:

private void buttonClip_Click(object sender, RoutedEventArgs e){ this.Clip = this.clipPath.Data;}

效果如下:

图形的效果与滤镜

在UIElement类的成员中可以找到BitmapEffect和Effect这两个属性,这两个属性都能用来为UI元素增加效果。BitmapEffect属性(已过时)使用CPU的运算能力为UI元素添加效果,Effect属性使用GPU的运算能力为UI元素添加效果

简单易用的BitmapEffect

BitmapEffect属性定义在UIEemet类中,它的数据类型是BitmapEffect类(抽象类),只能用BitmapEffect类的派生类实例为UIElement的BitmapEffect属性赋值。
BitmapEffect类的派生类包括如下几个:

  • BevelBitmapEffect:斜角效果。
  • BitmapEffectGroup:复合效果(可以把多个BitmapEffect组合在一起)。
  • BlurBitmapEffect:模糊效果。
  • DropShadowBitmapEffec:投影效果。
  • EmbossBitmapEffect:浮雕效果。
  • OuterGlowBitmapEffect:外发光效果。

每个效果都有自己的一系列属性可以调整,下面是一个DropShadowBitmapEffect的简单例子:

<Grid> <Button Content="Click Me" Grid.Column="0" Grid.Row="0" Margin="20">  <Button.BitmapEffect>   <DropShadowBitmapEffect Direction="-45" Opacity="0.75" ShadowDepth="7"/>  </Button.BitmapEffect> </Button></Grid>

效果如下:

丰富多彩的Effect

在绘图软件Photoshop中,使用滤镜插件能获得如下好处:

  • 提高工作效率。
  • 得到更专业的效果。
  • 对使用者的技术水平要求相对较低。

WPF引进了这种"滤镜插件"的思想——UIElement类的Effect属性,Effect属性的数据类型是Effect类(抽象类),可以接收Effect类的任何一个派生类的派生类实例作为它的值。

Effect类位于System.Windows.Media.Effects名称空间中,它的派生类有3个,分别是:

  • BlurEffect:模糊效果。
  • DropShadowEffect:投影效果。
  • ShaderEffect:着色器效果(抽象类)。

模糊和投影效果在编程中用的最多,.NET Framework内建了这两个效果,使用起来非常方便(用GPU进行渲染)。ShaderEffect(抽象类)是留给滤镜插件开发人员的接口,只要是派生自ShaderEffec的效果类就可以直接拿来用。

开发着色器效果需要使用Pixel Shader 语言(简写与Photoshop一样,也是PS)和一些DirectX的知识。大多数WPF开发人员需要的是现成的效果滤镜,可以使用官方的滤镜包,参考一些WPF中的滤镜特效——Effect Library

图形的变形

WPF中的"变形"一词含义很广,尺寸、位置、坐标系比例、旋转角度等的变化都算是变形
WPF中的变形与UI元素是分开的,如设计一个"向左旋转45度"的变形赋值给不同UI元素的变形控制属性,这些UI元素就都向左旋转45度了。

控制变形的属性有两个,分别是:

  • RenderTransform:呈现变形,定义在UIElement类中。
  • LayoutTransform:布局变形,定义在FrameworkElement类中。

FrameworkElement派生自UIElement,而控件的基类Control类又派生自FrameworkElement,所以在控件级别两个属性都能看到

这两个属性都是依赖属性,它们的数据类型都是Transform抽象类,Transform类的派生类实均可用来为这两个属性赋值。

Transform抽象类的派生类有如下一些:

  • MatrixTransform:矩阵变形,把容纳被变形UI元素的矩形顶点看作一个矩阵进行变形。
  • Rotate Transform:旋转变形,以给定的点为旋转中心,以角度为单位进行旋转变形。
  • ScaleTransform:坐标系变形,调整被变形元素的坐标系,可产生缩放效果。
  • SkewTransform:拉伸变形,可在横向和纵向上对被变形元素进行拉伸。
  • TranslateTransform:偏移变形,使被变形元素在横向或纵向上偏移一个给定的值。
  • TransformGroup:变形组,可以把多个独立变形合成为一个变形组、产生复合变形效果。

呈现变形

WPF的RenderTransform属性就是起到"呈现变形(Render Transform)"作用,让UI元素呈现出来的属性与它本来的属性不一样。

一个按钮本来处在Canvas或者Grid的左上角,可以使用RenderTransform属性让其呈现在右下角并且向右旋转45°,XAML代码如下:

<Window x:  

Grid的第一行的行高、第一列的列宽都由Button来决定,在窗体设计器里可以清晰地看到Button本身的位置并没有改变(第一行和第一列没有变化),但Button却出现在了右下(300,200)的位置,并向右旋转了45°。
效果如下:

用户并不能察觉到究竟是控件本身的位置、角度发生了改变,还是呈现的位置与角度发生了改变。

在窗体上移动UI元素本身会导致窗体布局的改变,而窗体布局的每一个(哪怕是细微的)变化都将导致所有窗体元素的尺寸测算函数、位置测算函数、呈现函数等的调用,造成系统资源占用激增、程序性能陡降。
使用呈现变形则不会遇到这样的问题,呈现变形只改变元素"出现在哪里",不牵扯布局的改变、只涉及窗体的重绘,制作动画时切记要使用RenderTransform

布局变形

与呈现变形不同,布局变形会影响窗体的布局、导致窗体布局的重新测算。因为窗体布局的重新测算和绘制会影响程序的性能,所以布局变形一般只用在静态变形上,而不用于制作动画

考虑这样一个需求:制作一个文字纵向排列的浅蓝色标题栏。如果我们使用呈现变形,代码如下:

<Window x:  

效果如下:

TextBox本身并没有改变,改变的只是它的显示,它的真实宽度仍然把宽度设为Auto的第一列撑得很宽。

分析需求,实际上需要的是静态改变TextBox的布局,因此应该使用LayoutTransform,对上面的代码做一处改动:

<TextBlock.LayoutTransform> <RotateTransform Angle="-90"/></TextBlock.LayoutTransform>

效果如下:

动画

动画本质就是在一个时间段内对象位置、角度、颜色、透明度等属性值的连续变化,有些是对象自身的属性,有些则是图形变形的属性。
注:WPF规定——可以用来制作动画的属性必须是依赖属性

变化即是运动,WPF的动画也是一种运动:

  • 运动的主体就是各种UI元素
  • 运动本身就是施加在UI元素上的一些Timeline派生类的实例

在实际工作中,往往就是先设计好一个动画构思、用一个Timeline派生类的实例加以表达,最后让某个UI元素来执行这个动画、完成动画与动画主体的结合

简单的动画由一个元素来完成就可以了,WPF把简单动画称为AnimationTimeline

复杂的(即并行的、复合的)动画就需要UI上的多个元素协同完成,包括有哪些UI元素参与动画、每个元素的动画行为是什么、动画何时开始何时结束等,WPF把一组协同的动画也称为Storyboard

Timeline、AnimationTimeline和Storyboard的关系如下所示:

简单独立动画

动画就是"会动的画","会动"指的就是能够让UI元素或元素变形的某个属性值产生连续变化

任何一个属性都有自己的数据类型(如UIElement的Width和Height属性为Double类型),几乎针对每个可能的数据类型,WPF的动画子系统都为其准备了相应的动画类(均派生自AnimationTimeline)。它们包括:

  • BooleanAnimationBase
  • ByteAnimationBase
  • CharAnimationBase
  • ColorAnimationBase
  • DecimalAnimationBase
  • DoubleAnimationBase
  • Int16AnimationBase
  • Int32AnimationBase
  • Int64AnimationBase
  • MatrixAnimationBase
  • ObjectAnimationBase
  • Point3DAnimationBase
  • PointAnimationBase
  • QuaternionAnimationBase
  • RectAnimationBase
  • Rotation3DAnimationBase
  • SingleAnimationBase
  • SizeAnimationBase
  • StringAnimationBase
  • ThicknessAnimationBase
  • Vector3DAnimationBase
  • VectorAnimationBase

上面列出的这些类都是抽象基类(带有Base后缀)。完整的情况下,这些抽象基类又能派生出3种具体动画,即简单动画关键帧动画沿路径运动的动画

如DoubleAnimationBase完整地派生出了3个具体动画,如下所示:

注:针对于int类型属性的Imt32AnimationBase只派生出Int32Animation和Int32AnimationUsingKeyFrames两个具体动画类。BooleanAnimationBase和CharAnimationBase的派生类则更少——只有关键帧动画类。

在WPF动画系统中Double类型的属性用得最多,而且DoubleAnimationBase的派生类也最完整,下面只讲述DoubleAnimationBase的派生类。

用户界面上只包含一个Button,这个Button的RenderTransform属性值是一个名为tt的TranslateTransform对象,改变这个对象的X和Y值就会让Buton的显示位置(而不是真实位置)变化,XAML代码如下:

<Grid> <Button Content="Move!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="60" Height="60" Click="Button_Click">  <Button.RenderTransform>   <TranslateTransform x:Name="tt" X="0" Y="0"/>  </Button.RenderTransform> </Button></Grid>

简单线性动画

"简单线性动画"是指仅由变化起点、变化终点、变化幅度、变化时间4个要素构成的动画

  • 变化时间(Duration属性):必须指定,数据类型为Duration。
  • 变化终点(To属性):如果没有指定变化终点,程序将采用上一次动画的终点或默认值。
  • 变化幅度(By属性):如果同时指定了变化终点,变化幅度将被忽略。
  • 变化起点(From属性):如果没有指定变化起点则以变化目标属性的当前值为起点。

每次单击按钮,按钮都会从起始位置(窗体的左上角)向窗体右下长宽不超出300像素的矩形内的某点运动,完成运动的时长是300毫秒,Button的Click事件处理器代码如下:

private void Button_Click(object sender, RoutedEventArgs e){ //TranslateTransform的X、Y属性均为Double类型,选用DoubleAnimation来使之产生变化 //声明dax和daY两个DoubleAnimation变量并分别为之创建引用实例 DoubleAnimation daX = new DoubleAnimation(); DoubleAnimation daY = new DoubleAnimation(); //指定起点 daX.From = 0D; daY.From = 0D; //指定终点 Random r = new Random(); daX.To = r.NextDouble() * 300; daY.To = r.NextDouble() * 300; //指定时长 Duration duration = new Duration(TimeSpan.FromMilliseconds(300)); daX.Duration = duration; daY.Duration = duration; // 动画的主体是TranslateTransform 变形,而非Button  //调用BeginAnimation方法,让daX、daY分别作用在TranslateTransform的XProperty、YProperty依赖属性上 this.tt.BeginAnimation(TranslateTransform.XProperty, daX); this.tt.BeginAnimation(TranslateTransform.YProperty, daY);}

以下几处值得注意:

  • 想让按钮从当前位置开始下一次动画,只需要把"daX.From=0D;"和"daY.From=0D;"两句代码移除即可。
  • 尽管表现出来的是Button在移动,但DoubleAnimation的作用目标并不是Button而是TranslateTransform实例。
  • 用来制作动画的属性必须是依赖属性,TranslateTransform的XProperty和YProperty就是两个依赖属性。
  • UIElement和Animatable两个类都定义有BeginAnimation方法,方法的调用者就是动画要作用的目标对象,两个参数分别指明被作用的依赖属性和设计好的动画

每次单击按扭,按钮都向窗体的右下角移动,则把事件处理器的代码改变成这样:

private void Button_Click(object sender, RoutedEventArgs e){ DoubleAnimation daX = new DoubleAnimation(); DoubleAnimation daY = new DoubleAnimation(); //指定幅度    daX.By = 100D; daY.By = 100D; //指定时长 Duration duration = new Duration(TimeSpan.FromMilliseconds(300)); daX.Duration = duration; daY.Duration = duration; // 动画的主体是TranslateTransform 变形,而非Button  this.tt.BeginAnimation(TranslateTransform.XProperty, daX); this.tt.BeginAnimation(TranslateTransform.YProperty, daY);}

高级动画控制

使用From、To、By、Duration几个属性进行组合就已经可以制作很多不同效果的动画了,如果想制作更加复杂或逼真的动画,还需要使用以下一些效果:

在这些属性中,EasingFunction是一个扩展性非常强的属性,取值是IEasingFunction接口类型,自带的派生类有十多种。

比如BounceEase可以产生乒乓球弹跳式的效果,把前面例子的代码改成这样:

private void Button_Click(object sender, RoutedEventArgs e){ DoubleAnimation daX = new DoubleAnimation(); DoubleAnimation daY = new DoubleAnimation(); //设置反弹 BounceEase be = new BounceEase(); be.Bounces = 3; // 弹跳3次 be.Bounciness = 3; //弹性程度,值越大反弹越低 daY.EasingFunction = be; //指定终点 daX.To = 300; daY.To = 300; //指定时长 Duration duration = new Duration(TimeSpan.FromMilliseconds(2000)); daX.Duration = duration; daY.Duration = duration; // 动画的主体是TranslateTransform 变形,而非Button  this.tt.BeginAnimation(TranslateTransform.XProperty, daX); this.tt.BeginAnimation(TranslateTransform.YProperty, daY);}

关键帧动画

动画是UI元素属性连续改变所产生的视觉效果。属性每次细微的变化都会产生一个新的画面,每个新画面就称为一"帧",帧的连续播放就产生动画效果。单位时间内播放的帧数越多,动画的效果就越细致。

简单动画只设置了起点和终点,之间的动画帧都是由程序计算出来并绘制的,程序员无法进行控制。

关键帧动画则允许程序员为一段动画设置几个"里程碑",动画执行到里程碑所在的时间点时,被动画所控制的属性值也必须达到设定的值,这些时间线上的"里程碑"就是关键帧

让Button在单击后用900毫秒的时长从左上角移动到右下角,但移动路线不是直接移动而是走"Z"字形,Button的Click事件处理器代码如下:

private void Button_Click(object sender, RoutedEventArgs e){ //创建两个DoubleAnimationUsingKeyFrames实例 //一个控制TranslateTransform的X属性,另一个控制Translate Transform的Y属性 //每个DoubleAnimationUsingKeyFrames各拥有三个关键帧用于指明X或Y在三个时间点(两个拐点和终点)应该达到什么样的值 DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames(); DoubleAnimationUsingKeyFrames dakY = new DoubleAnimationUsingKeyFrames(); // 设置动画总时长 dakX.Duration = new Duration(TimeSpan.FromMilliseconds(900)); dakY.Duration = new Duration(TimeSpan.FromMilliseconds(900)); //创建、添加关键帧 LinearDoubleKeyFrame x_kf_1 = new LinearDoubleKeyFrame(); LinearDoubleKeyFrame x_kf_2 = new LinearDoubleKeyFrame(); LinearDoubleKeyFrame x_kf_3 = new LinearDoubleKeyFrame(); x_kf_1.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300)); x_kf_1.Value = 200; x_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600)); x_kf_2.Value = 0; x_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900)); x_kf_3.Value = 200; dakX.KeyFrames.Add(x_kf_1); dakX.KeyFrames.Add(x_kf_2); dakX.KeyFrames.Add(x_kf_3); LinearDoubleKeyFrame y_kf_1 = new LinearDoubleKeyFrame(); LinearDoubleKeyFrame y_kf_2 = new LinearDoubleKeyFrame(); LinearDoubleKeyFrame y_kf_3 = new LinearDoubleKeyFrame(); y_kf_1.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300)); y_kf_1.Value = 0; y_kf_2.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600)); y_kf_2.Value = 180; y_kf_3.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(900)); y_kf_3.Value = 180; dakY.KeyFrames.Add(y_kf_1); dakY.KeyFrames.Add(y_kf_2); dakY.KeyFrames.Add(y_kf_3); //执行动画 this.tt.BeginAnimation(TranslateTransform.XProperty, dakX); this.tt.BeginAnimation(TranslateTransform.YProperty, dakY);}

在这组关键帧动画中,使用的是最简单的关键帧LinearDoubleKeyFrame,这种关键帧的特点就是只需你给定时间点(KeyTime属性)和到达时间点时目标属性的值(Value属性)动画就会让目标属性值在两个关键帧之间匀速变化

上面的代码中,为关键帧的KeyTime属性使用了KeyTime.FromTimeSpan静态方法,这样可以得到一个绝对时间点。使用KeyTime.FromPercent静态方法则可以获得以百分比计算的相对时间点,程序将整个关键帧动画的时长(Duration)视为100%

无论把dakX的Duration改为多少,三个关键帧都会将整个动画分割为均等的三段,代码改动如下:

//...x_kf_1.KeyTime = KeyTime.FromPercent(0.33);x_kf_1.Value = 200;x_kf_2.KeyTime = KeyTime.FromPercent(0.66);x_kf_2.Value = 0;x_kf_3.KeyTime = KeyTime.FromPercent(1);x_kf_3.Value = 200;//...

特殊的关键帧

DoubleAnimationUsingKeyFrames的KeyFrames属性的数据类型是DoubleKeyFrameCollection,此集合类可接收的元素类型为DoubleKeyFrame

DoubleKeyFrame是一个抽象类,前面使用的LinearDoubleKeyFrame就是它的派生类之一。DoubleKeyFrame的所有派生类如下:

  • LinearDoubleKeyFrame:线性变化关键帧,目标属性值的变化是直线性的、均匀的,即变化速率不变。
  • DiscreteDoubleKeyFrame:不连续变化关键帧,目标属性值的变化是跳跃性的、跃迁的。
  • SplineDoubleKeyFrame:样条函数式变化关键帧,目标属性值的变化速率是一条贝塞尔曲线。
  • EasingDoubleKeyFrame:缓冲式变化关键帧,目标属性值以某种缓冲形式变化。

4个派生类中最常用的是SplineDoubleKeyFrame(SplineDoubleKeyFrame可以替代LinearDoubleKeyFrame)。使用SplineDoubleKeyFrame可以非常方便地制作非匀速动画,因为它使用一条贝塞尔曲线来控制目标属性值的变化速率

这条用于控制变化速率的贝塞尔曲线的起点是(0,0)和(1,1),分别映射着目标属性的变化起点和变化终点,意思是目标属性值由0%变化到100%

这条贝塞尔曲线有两个控制点ControlPointl和ControlPoint2,意思是贝塞尔曲线从起点出发先向ControlPoint1的方向前进、再向ControlPoint2的方向前进、最后到达终点,形成一条平滑的曲线。

如果设置ControlPoint1和ControlPoint2的横纵坐标值相等,比如(0,0)、(0.5,0.5)、(1,1),则贝塞尔曲线成为一条直线,这时候SplineDoubleKeyFrame与LinearDoubleKeyFrame是等价的。

关键帧动画控制Button的位置变形、让Button横向移动,整个动画只有一个关键帧(使用的是SplineDoubleKeyFrame),变化速率控制曲线的两个控制点分别是(0,1)和(1,0),目标属性值会以"快一慢一快"的形式变化,Button的Click事件处理器代码如下:

private void Button_Click(object sender, RoutedEventArgs e){ //创建动画 DoubleAnimationUsingKeyFrames dakX = new DoubleAnimationUsingKeyFrames(); dakX.Duration = new Duration(TimeSpan.FromMilliseconds(1000)); // 创建、添加关键帧 SplineDoubleKeyFrame kf = new SplineDoubleKeyFrame(); kf.KeyTime = KeyTime.FromPercent(1); kf.Value = 400; KeySpline ks = new KeySpline(); ks.ControlPoint1 = new Point(0, 1); ks.ControlPoint2 = new Point(1, 0); kf.KeySpline = ks; dakX.KeyFrames.Add(kf); //执行动画 this.tt.BeginAnimation(TranslateTransform.XProperty, dakX);}

路径动画

使用DoubleAnimationUsingPath类,可以让目标对象沿着一条给定的路径移动

DoubleAnimationUsingPath需要一个PathGeometry来指明移动路径,PathGeometry的数据信息可以用XAML的Path语法书写。

PathGeometry的另一个重要属性是Source,Source属性的数据类型是PathAnimationSource枚举,枚举值可取X、Y或Angle:

  • 取值是PathAnimationSource.X,意味着这个动画关注的是曲线上每一点横坐标的变化;
  • 取值是PathAnimationSource.Y,意味着这个动画关注的是曲线上每一点纵坐标的变化;
  • 取值是PathAnimationSource.Angle,意味着这个动画关注的是曲线上每一点处切线方向的变化。

让Button沿着一条贝塞尔曲线做波浪形运动,程序的XAML代码如下:

<Grid x:Name="LayoutRoot"> <Grid.Resources>  <!--移动路径-->  <PathGeometry x:Key="movingPath" Figures="M 0,150 C 300,-100 300,400 600,120"/> </Grid.Resources> <Button Content="Move!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="60" Height="60" Click="Button_Click">  <Button.RenderTransform>   <TranslateTransform x:Name="tt" X="0" Y="0"/>  </Button.RenderTransform> </Button></Grid>

Button的Click事件处理器代码如下(添加自动返回和循环控制):

private void Button_Click(object sender, RoutedEventArgs e){ //从XAML代码中获取移动路径数据 PathGeometry pg = this.LayoutRoot.FindResource("movingPath") as PathGeometry; Duration duration = new Duration(TimeSpan.FromMilliseconds(600)); //创建动画 DoubleAnimationUsingPath dapX = new DoubleAnimationUsingPath(); dapX.PathGeometry = pg; dapX.Source = PathAnimationSource.X; dapX.Duration = duration; DoubleAnimationUsingPath dapY = new DoubleAnimationUsingPath(); dapY.PathGeometry = pg; dapY.Source = PathAnimationSource.Y; dapY.Duration = duration; //自动返回、永远循环 dapX.AutoReverse = true; dapX.RepeatBehavior = RepeatBehavior.Forever; dapY.AutoReverse = true; dapY.RepeatBehavior = RepeatBehavior.Forever; // 执行动画 this.tt.BeginAnimation(TranslateTransform.XProperty, dapX); this.tt.BeginAnimation(TranslateTransform.YProperty, dapY);}

场景

场景(Storyboard)就是并行执行的一组动画(前面讲述的关键帧动画则是串行执行的一组动画)

设计WPF的场景时,可按以下步骤进行:

  • 把一组独立的动画组织在一个Storyboard元素中、安排好它们的协作关系。
  • 指定哪个动画由哪个UI元素、哪个属性负责完成。
  • 为Storyboard选择一个恰当的触发时机,比如按钮按下时或下载开始时。

一旦触发条件被满足,动画场景就会开始执行,用户就会看到动画效果。

下面是一个Storyboard的例子,单击按钮后三个小球分别在不同的时间开始向右以不同的速度移动,程序的XAML代码如下:

<Grid Margin="6"> <!--布局控制--> <Grid.RowDefinitions>  <RowDefinition Height="38"/>  <RowDefinition Height="38"/>  <RowDefinition Height="38"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions>  <ColumnDefinition/>  <ColumnDefinition Width="60"/>      </Grid.ColumnDefinitions> <!--跑道(红)--> <Border BorderBrush="Gray" BorderThickness="1" Grid.Row="0">  <Ellipse x:Name="ballR" Height="36" Width="36" Fill="Red" HorizontalAlignment="Left">   <Ellipse.RenderTransform>    <TranslateTransform x:Name="ttR"/>   </Ellipse.RenderTransform>  </Ellipse> </Border> <!--跑道(绿)--> <Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="1">  <Ellipse x:Name="ballG" Height="36" Width="36" Fill="LawnGreen" HorizontalAlignment="Left">   <Ellipse.RenderTransform>    <TranslateTransform x:Name="ttG"/>   </Ellipse.RenderTransform>  </Ellipse> </Border> <!--跑道(蓝)-->     <Border BorderBrush="Gray" BorderThickness="1,0,1,1" Grid.Row="2">  <Ellipse x:Name="ballB" Height="36" Width="36" Fill="Blue" HorizontalAlignment="Left">   <Ellipse.RenderTransform>    <TranslateTransform x:Name="ttB"/>   </Ellipse.RenderTransform>   </Ellipse> </Border> <!--按钮--> <Button Content="Go!" Grid.Column="1" Grid.RowSpan="3" Click="Button_Click"/></Grid>

Button的Click事件处理器代码如下:

private void Button_Click(object sender, RoutedEventArgs e){ Duration duration = new Duration(TimeSpan.FromMilliseconds(600)); // 红色小球匀速移动 DoubleAnimation daRx = new DoubleAnimation(); daRx.Duration = duration; daRx.To = 400; //绿色小球变速运动 DoubleAnimationUsingKeyFrames dakGx = new DoubleAnimationUsingKeyFrames(); dakGx.Duration = duration; SplineDoubleKeyFrame kfG = new SplineDoubleKeyFrame(400, KeyTime.FromPercent(1.0)); kfG.KeySpline = new KeySpline(1, 0, 0, 1); dakGx.KeyFrames.Add(kfG); //蓝色小球变速运动 DoubleAnimationUsingKeyFrames dakBx = new DoubleAnimationUsingKeyFrames(); dakBx.Duration = duration; SplineDoubleKeyFrame kfB = new SplineDoubleKeyFrame(400, KeyTime.FromPercent(1.0)); kfB.KeySpline = new KeySpline(0, 1, 1, 0); dakBx.KeyFrames.Add(kfB); //创建场景 Storyboard storyboard = new Storyboard(); Storyboard.SetTargetName(daRx, "ttR"); Storyboard.SetTargetProperty(daRx, new PropertyPath(TranslateTransform.XProperty)); Storyboard.SetTargetName(dakGx, "ttG"); Storyboard.SetTargetProperty(dakGx, new PropertyPath(TranslateTransform.XProperty)); Storyboard.SetTargetName(dakBx, "ttB"); Storyboard.SetTargetProperty(dakBx, new PropertyPath(TranslateTransform.XProperty)); storyboard.Duration = duration; storyboard.Children.Add(daRx); storyboard.Children.Add(dakGx); storyboard.Children.Add(dakBx); storyboard.Completed += (a, b) => { MessageBox.Show(ttR.X.ToString()); }; storyboard.Begin(this);}

使用C#代码实现Storyboard非常复杂,除了拿来做研究或遇到非得使用C#动态创建Storyboard的情况,不然都是用XAML代码创建Storyboard

Storyboard一般都放在UI元素的Trigger里,Trigger在触发时会执行标签中的Storyboard实例

为Buton添加Trigger并去掉对Click事件的订阅,XAML代码其他的部分不做任何改动,代码如下:

<Button Content="Go!" Grid.Column="1" Grid.RowSpan="3"> <Button.Triggers>  <EventTrigger RoutedEvent="Button.Click">   <BeginStoryboard>    <Storyboard Duration="0:0:0.6">     <!--红色小球动画-->     <DoubleAnimation Duration="0:0:0.6" To="400" Storyboard.TargetName="ttR" Storyboard.TargetProperty="X"/>     <!--绿色小球动画-->     <DoubleAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetName="ttG" Storyboard.TargetProperty="X">      <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="1,0,0,1"/>     </DoubleAnimationUsingKeyFrames>     <!--红蓝小球动画-->     <DoubleAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetName="ttB" Storyboard.TargetProperty="X">      <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="0,1,1,0"/>     </DoubleAnimationUsingKeyFrames>    </Storyboard>   </BeginStoryboard>  </EventTrigger> </Button.Triggers></Button>








原文转载:http://www.shaoqun.com/a/654727.html

跨境电商:https://www.ikjzd.com/

prezi:https://www.ikjzd.com/w/1751

海维:https://www.ikjzd.com/w/1891


XAML绘图本身就是矢量的,支持各式各样的填充和效果,还可以添加滤镜。XAML矢量图是借助MicrosoftExpressionStudio中的Design和Blend两个工具画出来的。动画本质就是在一个时间段内对象位置、角度、颜色、透明度等属性值的连续变化,有些是对象自身的属性,有些则是图形变形的属性。变化即是运动,WPF的动画也是一种运动,运动的主体就是各种UI元素,运动本身就是施加在UI元素
粉丝通:https://www.ikjzd.com/w/743
zappos:https://www.ikjzd.com/w/330
bol:https://www.ikjzd.com/w/291
遇到亚马逊listing被封冻结的处理办法:https://www.ikjzd.com/tl/107919
办公室和老板嗯啊 心机老板想要我:http://www.30bags.com/a/254921.html
口述:无性新婚夜 他逼我离开他:http://www.30bags.com/m/a/253835.html

SqlServer存储过程的创建与使用

什么是存储过程?

T-SQL中的存储过程,非常类似于net语言中的方法,它可以重复调用。当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句。

这样就可以提高存储过程的性能。

  1.  存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行。
  2.  存储过程中可以包含逻辑控制语句和数据操纵语句,它可以接受参数、输出参数、返回单个或多个结果集以及返回值。
  3.  由于存储过程在创建时即在数据库服务器上进行了编译并存储在数据库中,所以存储过程运行要比单个的SQL语句块要快。
  4.  同时由于在调用时只需用提供存储过程名和必要的参数信息,所以在一定程度上也可以减少网络流量、简单网络负担。

 

 


 

存储过程的优点

1、存储过程允许标准组件式编程

存储过程创建后可以在程序中被多次调用执行,而不必重新编写该存储过程的SQL语句。

而且数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性。

2、存储过程能够实现较快的执行速度

如果某一操作包含大量的T-SQL语句代码,分别被多次执行,那么存储过程要比批处理的执行速度快得多。

因为存储过程是预编译的,在首次运行一个存储过程 时,查询优化器对其进行分析、优化,并给出最终被存在系统表中的存储计划。

而批处理的T-SQL语句每次运行都需要预编译和优化,所以速度就要慢一些。

3、存储过程减轻网络流量

对于同一个针对数据库对象的操作,如果这一操作所涉及到的T-SQL语句被组织成一存储过程,

那么当在客户机上调用该存储过程时,网络中传递的只是该调用语句,否则将会是多条SQL语句。

从而减轻了网络流量,降低了网络负载。

4、存储过程可被作为一种安全机制来充分利用

系统管理员可以对执行的某一个存储过程进行权限限制,从而能够实现对某些数据访问的限制,避免非授权用户对数据的访问,保证数据的安全。

 

 


 存储过程的缺点

1、运行速度

对于很简单的sql,存储过程运行速度没有什么优势。 

2、代码可读性差,不易于维护

存储过程的开发调试要比一般程序困难(老版本DB2还只能用C写存储过程,更是一个灾难)。

代码可读性差,不易于难维护。

3、可移植性差

由于存储过程将应用程序绑定到SQLServer,因此使用存储过程封装业务逻辑将限制应用程序的可移植性。

如果应用程序的可移植性在您的环境中非常重要,则将业务逻辑封装在不特定于RDBMS的中间层中可能是一个更佳的选择。

 


存储过程的基本语法

变量的声明:
声明变量时必须在变量前加@符号
declare @num int

变量的赋值:
变量赋值时变量前必须加set
set @num= 30

声明多个变量:
declare @name varchar(10),@num int

if语句的使用:

declare @d intset @d = 1IF @d = 1BEGIN PRINT '正确' 
END
ELSE BEGIN
PRINT '错误'
END

 

多条件选择语句:

declare @today intdeclare @week nvarchar(3)set @today=3set @week= case  when @today=1 then '星期一'  when @today=2 then '星期二'  when @today=3 then '星期三'  when @today=4 then '星期四'  when @today=5 then '星期五'  when @today=6 then '星期六'  when @today=7 then '星期日'  else '值错误'endprint @week

 

循环语句:

DECLARE @i INTSET @i = 1WHILE @i<1000000 BEGINset @i=@i+1END

 

定义游标:

DECLARE @cur1 CURSOR FOR SELECT .........OPEN @cur1FETCH NEXT FROM @cur1 INTO 变量WHILE(@@FETCH_STATUS=0)BEGIN处理.....FETCH NEXT FROM @cur1 INTO 变量ENDCLOSE @cur1DEALLOCATE @cur1


存储过程的分类

1、系统存储过程

系统存储过程是系统创建的存储过程,目的在于能够方便的从系统表中查询信息或完成与更新数据库表相关的管理任务或其他的系统管理任务。

系统存储过程主要存 储在master数据库中,以"sp"下划线开头的存储过程。

尽管这些系统存储过程在master数据库中,但我们在其他数据库还是可以调用系统存储过 程。

有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。

1.1、系统存储过程sql示例

--表重命名exec sp_rename 'stu', 'stud';--列重命名exec sp_rename 'stud.name', 'sName', 'column';exec sp_help 'stud';--重命名索引exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';exec sp_help 'student';--查询所有存储过程select * from sys.objects where type = 'P';select * from sys.objects where type_desc like '%pro%' and name like 'sp%';

2、自定义存储过程

所谓自定义存储过程,是指为了完成某一段特定的功能需求,在用户数据库中利用t-sql自行编辑的语句集合,在用户自定义的过程中可以有输入参数,返回的输出参数及返回至客户端的信息与结果 。

如果在存储过程名称前加了"##"符号,表示创建的存储过程是临时的全局性的;

如果前面的为"#"符号,表示所创建的存储过程是临时的局部的,该存储过程只能在创建它的会话中使用。

以上两种存储过程创建后都存放在tempdb数据库中。

用户自定义存储过程还可以细分为t-sql语言存储过程和CLR存储过程。CLR存储过程是指利用.NET框架公共语言编辑的存储过程,既可以接受用户提供的参数又可以返回存储过程的运行结果,通常用作某个类的公共静态方法。

 2.1、创建不带参数存储过程

--创建一个返回结果集的存储过程(proc或者procedure均可)if (object_id('proc_get_student', 'P') is not null)--判断存储过程是否存在 另外一种 if (exists (select * from sys.objects where name = 'proc_get_student'))//drop proc proc_get_student --删除存储过程gocreate proc proc_get_student --创建存储过程asselect * from student; --结果集--调用执行存储过程,得到返回集(exec或者execute均可)exec proc_get_student;

2.2、修改存储过程

--修改存储过程alter proc proc_get_studentasselect * from student; --修改后的SQL语句--调用执行存储过程,得到返回集(exec或者execute均可)exec proc_get_student;

2.3、带参数存储过程

--创建一个返回结果集的存储过程(proc或者procedure均可)if (object_id('proc_find_stu', 'P') is not null)--判断存储过程是否存在drop proc proc_find_stugocreate proc proc_find_stu(@startId int, @endId int)--两个参数asselect * from student where id between @startId and @endId --查询语句go--调用执行存储过程,2,4为参数exec proc_find_stu 2, 4;

2.4、带通配符参数存储过程

--创建一个返回结果集的存储过程(proc或者procedure均可)if (object_id('proc_findStudentByName', 'P') is not null)drop proc proc_findStudentByNamegocreate proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%')asselect * from student where name like @name and name like @nextName;go--调用执行存储过程exec proc_findStudentByName;exec proc_findStudentByName '%o%', 't%';

2.5、带输出参数存储过程

--创建一个返回结果集的存储过程(proc或者procedure均可)if (object_id('proc_getStudentRecord', 'P') is not null)drop proc proc_getStudentRecordgocreate proc proc_getStudentRecord(@id int, --默认输入参数@name varchar(20) out, --输出参数@age varchar(20) output--输入输出参数)asselect @name = name, @age = age from student where id = @id and sex = @age;go--调用执行存储过程declare @id int,@name varchar(20),@temp varchar(20);set @id = 7;set @temp = 1;exec proc_getStudentRecord @id, @name out, @temp output;select @name, @temp;print @name '#' @temp;

3、扩展存储过程

通常以"xp_"为前缀标识,在sql server系统外通过执行动态链接库,即DLL文件,来实现的功能,该存储过程经常使用API接口进行编辑,可以加载到sql server实例的地址空间里试试运行。

在sql server常见的扩展存储过程有:

  • xp_enumgroups 指定WINDOWS本地组列表在WINDOWS域中定义的全局组表
  • xp_findnextmsg 接受输入的邮件ID号,返回输出的邮件ID号
  • xp_grantlogin     给用户分配对sql server2012系统的权限
  • xp_logevent    把用户自定义消息输入到sql server日志文件或WINDOWS系统事件查看器中
  • xp_loginconfig 显示sql server 2012实例运行时登陆的安全配置

 

好了,我们就介绍到这里吧,

拜拜,我们下次见。

 


欢迎关注订阅我的微信公众平台【熊泽有话说】,更多好玩易学知识等你来取
作者:熊泽-学习中的苦与乐
公众号:熊泽有话说
出处: https://www.cnblogs.com/xiongze520/p/14595601.html
创作不易,任何人或团体、机构全部转载或者部分转载、摘录,请在文章明显位置注明作者和原文链接。  

 









原文转载:http://www.shaoqun.com/a/654723.html

跨境电商:https://www.ikjzd.com/

cicpa:https://www.ikjzd.com/w/1375

飞书互动:https://www.ikjzd.com/w/1319.html


什么是存储过程?T-SQL中的存储过程,非常类似于net语言中的方法,它可以重复调用。当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句。这样就可以提高存储过程的性能。存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行。存储过程中可以包含逻辑控制语句和数据操纵语句,它可以接受参数、输出参数
hts:https://www.ikjzd.com/w/525
王惟:https://www.ikjzd.com/w/1744
stadium:https://www.ikjzd.com/w/2729
跨境人必读:细数那些能减免关税的原产地证书!:https://www.ikjzd.com/home/21226
国内电商市场饱和的当下,新跨境电商时代如何"求新、求变"?:https://www.ikjzd.com/home/20826
那一夜我解开了老师的裙子 老师引诱我进了她身体:http://www.30bags.com/a/249732.html

库里回归砍32分武神摘21+9 勇士5人上双力擒公牛_比赛

原标题:库里回归砍32分武神摘21+9 勇士5人上双力擒公牛

北京时间3月30日消息,2020-21赛季NBA常规赛继续进行,金州勇士队在主场迎战芝加哥公牛队。本场比赛,库里完成复出,最终,勇士队以116-102战胜公牛队。

单节比分:29-34,31-31,25-31,17-20(公牛队在前)

数据方面,公牛队这边,武切维奇21分9篮板6助攻,威廉姆斯14分6篮板,萨托兰斯基14分8助攻,拉文12分,赛迪斯-杨10分,马尔卡宁13分6篮板。勇士队这边,库里32分5篮板6助攻,维金斯21分5助攻,乌布雷18分11篮板,怀斯曼12分5篮板,格林11分5篮板9助攻。

比赛开始后,威廉姆斯跳投得手,帮助公牛队首开纪录。之后,勇士队接连回应,连续取分,取得微弱的领先优势。之后,虽然公牛队奋力追分,但勇士队也屡有回应,一直保持微弱的领先优势。到了本节后半段,勇士队在进攻端突然哑火,随后,武切维奇通过罚球帮助公牛队追平比分。随后,阿奇迪科诺飙中三分,直接帮助公牛队完成反超。而后,库里飙中三分,帮助勇士队止血。之后,两队互有攻守,比分交错上升。到了本节末段,公牛队突然哑火,勇士队趁机再度取得领先。本节结束时,勇士队以34-29暂时领先公牛队。

第二节比赛开始后,马尔卡宁跳投得手,帮助公牛队追分。随后,虽然乌布雷上篮得手,但公牛队随即连续彪中三分,直接反超比分。随后,乌布雷再强攻得手,帮助勇士队止血。而后,两队再度陷入拉锯战态势,两队均保持较高的进攻效率,比分交错上升,一直紧咬。到了本节末段,勇士队再度取得微弱的领先优势,而后,虽然公牛队接连强攻内线追分,但是勇士队内外开花,也屡有回应。本节结束时,勇士队以65-60暂时领先公牛队。

第三节比赛开始后,拉文跳投得手,帮助公牛队追分。而后,萨托兰斯基打成2+1,帮助公牛队追平比分。此后,两队多次战平。而后,维金斯连续强攻禁区砍分,帮助勇士队再度取得6分的领先优势。而后,武切维奇连续强攻内线,帮助公牛队止血。勇士队也利用维金斯的再度强攻保持领先优势。到了本节中段,库里也连续砍分,帮助勇士队保持领先。随后,勇士队突然哑火,公牛队连续砍分将分差直接缩小至仅差2分。随后,库里持球推进过半场后中距离出手稳稳命中,帮助球队止血。随后,两队均陷入得分荒,而库里通过造杀伤及外线的三分帮助勇士队取得9分的领先。到了本节末段,库里与格林连续砍分,直接将分差扩大至两位数,打停公牛队。本节结束时,勇士队以96-85暂时领先公牛队。

第四节比赛开始后,公牛队在进攻端屡屡难以打破僵局,而勇士队则利用贝兹莫尔的三分与普尔的暴扣将分差直接扩大至16分。随后,拉文通过造杀伤帮助公牛队止血。此后,虽然公牛队奋力追分,但是勇士队均能接连回应,将分差一直保持在10分以上。到了本节接近中段,普尔空切上篮得手,帮助勇士队将分差再度扩大至16分,直接打停公牛队。此后,两队陷入拉锯战,比分交错上升,勇士队一直保持15分以上的领先优势。到了本节末段,两队直接换上替补阵容,比赛也进入到垃圾时间。最终,勇士队以116-102战胜公牛队。(豌豆)

首发阵容:

公牛队首发:萨托兰斯基、拉文、威廉姆斯、赛迪斯-杨、武切维奇

勇士队首发:库里、乌布雷、维金斯、格林、怀斯曼返回搜狐,查看更多

责任编辑:

原文转载:http://sport.shaoqun.com/a/511739.html

跨境电商:https://www.ikjzd.com/

飞书互动:https://www.ikjzd.com/w/1319

友家快递:https://www.ikjzd.com/w/1341


原标题:库里回归砍32分武神摘21+9勇士5人上双力擒公牛北京时间3月30日消息,2020-21赛季NBA常规赛继续进行,金州勇士队在主场迎战芝加哥公牛队。本场比赛,库里完成复出,最终,勇士队以116-102战胜公牛队。单节比分:29-34,31-31,25-31,17-20(公牛队在前)数据方面,公牛队这边,武切维奇21分9篮板6助攻,威廉姆斯14分6篮板,萨托兰斯基14分8助攻,拉文12分,赛
let go:https://www.ikjzd.com/w/825
prime day:https://www.ikjzd.com/w/131.html
史泰博:https://www.ikjzd.com/w/2112
商标在海外被恶意抢注,无法维权怎么办?:https://www.ikjzd.com/home/108779
分享购物信息就有奖励 亚马逊推出购物小组计划:https://www.ikjzd.com/home/132491
口述五十老妇下面水还多_五十的女人做很爽:http://lady.shaoqun.com/m/a/273839.html

高血压患者,是不是比正常人寿命短?短多少?医生给出肯定答复

核心提示:综合多个研究,高血压确实会影响寿命,但是没有缩短20年那么夸张。有研究人员认为,高血压对寿命的影响,取决于是否接受治疗。

得了高血压,寿命会不会比别人短?短多少年?在心内科门诊,这是患者最常提起的问题之一,也是很多人的牵挂。

"我老公才33岁就高血压了,现在每天吃药,饮食不注意,怎么说也不听,还总是说'活多久,看命',怎么办?"

"我大姑高血压,63岁去世,我二姑也是,62岁去世,我朋友也是高血压,42岁去世,我同学高血压,40岁去世。所以我觉得高血压风险肯定比正常人高。"

生活中,很多人都有这样的疑问:高血压患者寿命真的比正常人短吗?

一、高血压减寿20年?实际没那么夸张

此前有文章称,高血压患者的平均患病年龄为32岁,在不治疗的前提下,平均死亡年龄在51岁,而正常人的平均寿命为71岁。也就是说,在患高血压之后,高血压患者的寿命缩短了20年。

不过,这个说法虽然广为流传,但证据不充分,可以可信度不高

更可靠的说法来自英国的一项长达40年的随访调查,统计数据发现,在1.9万名40-69岁的志愿者中,年龄在50岁以上且吸烟、高血压、高胆固醇的人平均寿命为73岁。年龄在50岁以上,没有吸烟、高血压和胆固醇的人平均寿命为83岁,与前者相差了10岁。如果再加上肥胖、糖尿病等危险因素,两者之间的平均寿命则相差了15岁

综合多个研究,高血压确实会影响寿命,但没有缩短20年那么夸张。有研究人员认为,高血压对寿命的影响,取决于是否接受治疗。

20世纪80年代,美国一所大学开展了一项长达22年的研究。研究人员把高血压志愿者随机分成了2组,研究开始的4.5年,一组接受降压药氯噻酮,另一组接受安慰剂治疗。4.5年之后,两组高血压志愿者都接受降压治疗。

结果发现,接受了4.5年降压药氯噻酮治疗的高血压患者,死亡率明显比接受了4.5年安慰剂治疗的高血压患者低

综合来看,高血压对寿命有一定的影响,但只要及早接受科学系统的降压治疗,同时积极改善生活方式,就能降低高血压对寿命的影响。

二、新研究:血压降至120,寿命再延长3年

一项发表在著名心血管期刊《循环》(Circulation)的SPRINT(收缩压干预试验)显示,血压降至120mmHg,可能使高血压患者预期寿命延长0.5-3不等

实验人员对9361名年龄在50岁以上的高心血管风险人群进行了研究,他们都具有无糖尿病、收缩压在130-180 mmHg的共性。结果发现,强化血压控制(<120mmHg)的患者比标准血压控制(<140mmHg)的患者,心血管事件和心血管死亡率都有效降低了,预期寿命也相对延长。

同时,研究人员强调,高血压患者一定要注意接受规范的降压治疗,同时注意生活管理,才能有效降低心血管风险,延长寿命。

三、给高血压患者的健康忠告

高血压是常见的慢性病,如果不及时治疗或者治疗不规范,导致血压长期波动,可能引发心肌梗死、脑卒中、心力衰竭等慢性病,严重影响生活质量和生存期。

因此,高血压患者应该牢牢记住以下健康忠告:

·牢记降压目标

只有血压达标,才能最大限度地降低心血管事件风险和死亡风险。因此,高血压患者应了解自己的降压目标。

由于个人情况不同,高血压患者的降压目标有所差异。一般来说,大多数高血压患者降至140/90mmhg以下即可,年龄在65岁以上的高血压患者降压目标可以适当放宽,降至150/90mmhg以下即可。但这只是初级目标,有能力的患者应继续往更健康的血压努力。

·合理的膳食

在饮食上,要避免高钠、低钾饮食,尤其要减少盐分的摄入,每日摄入盐分应少于5g;还要减少动物食品和动物油的摄入,把动物油换成玉米油、橄榄油等植物油,并坚持适量的原则;避免饮食单一化,适量补充蛋白质、钙和维生素。

生活中,适合高血压患者的食物有土豆、蘑菇等富含钾、钙的植物类食物;燕麦、玉米、红薯等富含膳食纤维的粗粮和杂粮;低脂牛奶和奶制品、豆腐和豆制品、鱼类、瘦肉等富含优质蛋白,且脂肪和胆固醇含量较低的食物

·过胖需减重

如果体重超重或肥胖,在接受降压治疗的同时,还要积极减重

研究发现,每减少1kg体重,收缩压可降低4mmHg。不过,减重要用科学的方法,切忌绝食、吃减肥药等不健康的方式,同时还要遵循循序渐进的原则,不提倡快速减重,这样一方面容易造成体重反弹,另一方面也会导致血压波动。

·定期锻炼

高血压患者可以根据个人情况,选择不同的运动方式,比较推荐的有慢跑、游泳、爬山等有氧运动,推、拉、举等力量练习,以及羽毛球、瑜伽、太极拳等综合功能练习。建议每周运动2-3次,每次运动30分钟以上。由于早上是心血管事件的高发时间,所以推荐在下午或傍晚进行锻炼

高血压是终身慢性病,需要长期吃药控制,同时管理生活方式。虽然寿命会受到影响,但只要采取科学的降压方法,就能将寿命影响降到最低,还能有效提高生活质量。


参考资料:


[1]高血压减寿20年?过于夸张,不过患者寿命确实受影响 | 较真医学.全民较真.2017-08-01

[2]高血压生活管理指南,收藏了!.医学界神经病学频道.2018-12-08

未经作者允许授权,禁止转载


原文转载:http://health.shaoqun.com/a/211111.html

跨境电商:https://www.ikjzd.com/

蜜芽宝贝官网:https://www.ikjzd.com/w/1320

prime:https://www.ikjzd.com/w/129


核心提示:综合多个研究,高血压确实会影响寿命,但是没有缩短20年那么夸张。有研究人员认为,高血压对寿命的影响,取决于是否接受治疗。 得了高血压,寿命会不会比别人短?短多少年?在心内科门诊,这是患者最常提起的问题之一,也是很多人的牵挂。"我老公才33岁就高血压了,现在每天吃药,饮食不注意,怎么说也不听,还总是说'活多久,看命',怎么办?""我大姑高血压,63岁去世,我二姑也是,62岁去世,我朋友也是
铭宣海淘:https://www.ikjzd.com/w/1551
tenso:https://www.ikjzd.com/w/1552.html
easy buy:https://www.ikjzd.com/w/2162
2019年亚马逊押注零售:实体店扩大2小时送货范围:https://www.ikjzd.com/home/14361
马云写的福字火了 扫出敬业福免费送猪肉:https://www.ikjzd.com/home/16222
个护产品销量增速全品类第三!海外消费者最爱买啥?:https://www.ikjzd.com/home/143317

无脑人:我们真的需要大脑吗?|柳叶刀



  来源:利维坦

  导语/ Introduction

  2019年11月,《自然》杂志上发表了一篇论文,名为《没有大脑的生命:神经放射学和行为学证据表明,严重脑积水情况下,神经可塑性是维持大脑功能的必要条件》(Life without a brain: Neuroradiological and behavioral evidence of neuroplasticity necessary to sustain brain function in the face of severe hydrocephalus),该论文指出,一只患严重脑积水的小鼠存活了下来,不仅如此,其空间记忆、嗅觉、听觉、触觉等均和普通小鼠无异,从而引出生存的"最低限度"讨论。

  长期以来,科学家一直认为意识是由于脑内神经元之间广泛存在的协调活动引起的。换言之,意识诞生于大脑亦是一个普遍性共识,然而,"无脑人"的案例又该如何解释呢?



  在一次讨论中,有位德高望重的人(我不会透露这个人是谁)告诉我:"我认为自我存在于心脏!而不是大脑!那些声称意识存在于大脑的科学论断真是让我发笑。我坚信未来的科学家一定也会认为,自我实际存在于心脏。"

  此人还进一步提及我们是用心脏"思考"。出于对他的尊敬,我没说什么。但我一直在腹诽:"这太荒唐了!"此人笃信东方的瑜伽修行、伊斯兰苏菲派和佛教思想,这让我多少理解他为何会说出这样的话,但同时(作为一个相信科学的人),我对此全盘否定。尽管我本人非常尊重那些教派思想(如佛教),但当它们和实证相矛盾时,我还是心存质疑。

  这位人士随即称他有据可依。他提到了一些故事,说医生给正常人做脑部扫描后,发现他们的头骨中没有大脑,只有水。听到这里,我又在想这太荒谬了。这可能只是经过夸张渲染的某些趣闻轶事,在口耳相传中渐渐失真。

  因此,当我发现这些故事真实存在时,我既震惊又羞愧。

  1980年12月,罗杰·莱文(Roger Lewin)在《科学》(Science)期刊上发表了文章,题为"我们真的需要大脑吗?"

  这篇文章基于英国神经学家约翰·洛伯(John Lorber,1915-1996)对脑水肿患者的案例研究,并且详细探究了其中一个案例:一名大学生的IQ高达126,拿了数学专业的一等荣誉学位,社交表现也完全正常,但在脑部扫描中,他们发现他实际上没有大脑。

 没有大脑组织的头骨内部。 没有大脑组织的头骨内部。

  正常人的大脑皮层厚度一般为4.5毫米,但他只有薄薄的1毫米,剩下的部分充满了水样脑脊液。这一现象可能是因为脑脊液不断积蓄,导致颅内压升高、颅内空间减少,因此大脑皮层向外侧(即向头骨)填充发育缓慢。这也就意味着,大脑皮层沟回越深,发育期间越不受压制,脑结构相对而言就越完整(尽管大脑皮层在压力下仍会收缩,也可能达不到正常状态)。

  这一案例被详细记录了下来,并引发了热议,连带着那篇文章也受到关注。最主流的解释似乎是神经自适应功能(也被称为搪塞之辞)。不过,这些现象直至今天仍很难解释。正如荣誉退休教授威廉·里维尔(William Reville)所说:

  "我当然解释不了洛伯的发现,但我想指出,在某些案例中,大脑显示出极强的适应力,尽管其容量和结构被严重挤压变形,但仍能以一种近似于我们熟知的'正常'模式为人体服务。"

  洛伯还发现了其他有趣的案例,证明了无脑现象并非独一无二。事实上,在他的研究中,一半的人的大脑中超过95%的区域都是脑脊液,但IQ指数仍然超过100。

约翰·洛伯对脑水肿患者脑部的扫描图。约翰·洛伯对脑水肿患者脑部的扫描图。

  我到现在也不明白,为什么这一现象还未撼动神经学界。我认为它简直是惊天动地。

  也许神经自适应理论能够解释某些功能的转移,但可以肯定的是,比起一个1.5千克重的正常大脑,一个只有50~150克(且只有1毫米厚的大脑皮层)的大脑的认知功能肯定有着巨大缺陷。我们的神经学理论经常将大脑皮层和具信息处理功能的脑区联系起来,比如感觉皮层,运动皮层,听觉和视觉皮层等等。与之相关的还有一些其他的功能,如抽象能力,计算,逻辑思维和记忆等。

  很明显,所有这些脑区似乎都被挤压至1毫米厚的皮层上,且仍然正常运转。尽管这篇文章中没有提及形态改变,但更多的近期研究表明,脑水肿患者在神经元的轴突、细胞骨架和突触等方面有很大损伤;神经元死亡数相对较少,但也有继发性变化。

2007年,英国医学权威杂志《柳叶刀》上的病例让世人震惊。这名法国男子44岁,是一名政府公务员。当时,他因为左腿有些毛病才去看的医生。结果医生在为其进行大脑CT和核磁共振扫描后,就惊讶地发现,他的脑室内充满了脑脊液。那些本该正常的脑组织,则因脑脊液的挤压薄得就像一张纸。脑力测试显示,他的智商为75,虽然比普通人低分略低,但还远不止于被列为智力障碍行列。而且他的生活过得也很美满,几乎没有受影响。事实上,他早已结婚并育有两个孩子,而且还是一位政府公务人员。2007年,英国医学权威杂志《柳叶刀》上的病例让世人震惊。这名法国男子44岁,是一名政府公务员。当时,他因为左腿有些毛病才去看的医生。结果医生在为其进行大脑CT和核磁共振扫描后,就惊讶地发现,他的脑室内充满了脑脊液。那些本该正常的脑组织,则因脑脊液的挤压薄得就像一张纸。脑力测试显示,他的智商为75,虽然比普通人低分略低,但还远不止于被列为智力障碍行列。而且他的生活过得也很美满,几乎没有受影响。事实上,他早已结婚并育有两个孩子,而且还是一位政府公务人员。

  这对沟通功能会造成很大影响,但很多患者的智力和认知水平仍在正常范围内。我们难道不应该反思一下我们现下的认知或研究方向吗?现在,我们关于沟通和信号传递的多数理论都仍以大脑为基础。

  因为大脑皮层变得更加扁平、容量更小,神经元之间建立新联系的能力也会削弱。通常来说,这些新联系是我们理解大脑活动、解释学习和记忆机制的基础。

  例如,实验已证明网格细胞存在于内嗅皮层,和位置细胞(位置细胞的发现者们获得了2014年诺贝尔生理学或医学奖)一起构成动物和人类的导航系统。网格细胞的机制非常复杂,但一大核心在于"模块化组织"。这是神经元有着"空间"整合功能的证据。现在我十分好奇,当这些也被挤压变形,大脑是否还能够正常运行导航系统?

2016年,《柳叶刀》发表的一篇论文中,显示了一位62岁的女性患者脑积水的扫描图。该患者(有高血压病史和2型糖尿病)在入院前精神状态一直很好。2016年,《柳叶刀》发表的一篇论文中,显示了一位62岁的女性患者脑积水的扫描图。该患者(有高血压病史和2型糖尿病)在入院前精神状态一直很好。

  如果我们认为薄薄的1毫米大脑皮层之上,认知、意识和潜意识等过程仍能正常运行,那么我们同时也得承认所有这些(包括意识)过程相对简单得多,也更容易解释。由此而言,大脑应该不会无限复杂。这种看法也支撑了以下观点(这同样出于我个人的直觉),即意识与大脑发育而成的特定构造更加相关,而非取决于某个部位,和/或特定脑区的复杂度。

  总的来说,该文使我的观点更具可塑性。它也表明,尤其是在社会科学领域,我们有时会基于总体或总数得出结论。我们从单个数据的集合中找到最匹配或归纳性的结论,但却忽略了个体数据本身的重要性。

  那这是否意味着

  我们是在用心思考?

  这听起来同样荒谬,因为我们知道心脏内大部分是心肌组织。

  我已不再牢牢拥护先前的看法,但仍试图在这片混沌之海里打捞一下,而我确实发现了一些很有趣的事情。

  2003年发表于《卫报》的一篇文章,以一些轶事为基石,提出了"移植记忆"的概念。很显然,这种情况发生在一些接受了心脏移植的患者身上。他们发展出新的爱好,或者性格有了变化,而这些爱好或性格都来自心脏捐赠者。

  这篇文章还提到了别的有趣概念。其一,"肠肌神经丛"是内脏中的第二大脑,可能掌管着情感反应或"直觉"。其二,遍布人体的神经肽可以提供"自我"感,并承载情感和记忆。

  神经肽可能提供  神经肽可能提供"自我"感,承载情感和记忆。

  总的说来,我认为这不太可信,至少还未达到能解释我们眼中事物全貌的程度。不过,提出或正在研究这些观点的人,似乎都是科学家,而非东方神秘主义者。

  我还在《Namah》期刊上找到了一篇好文(但我不太确定期刊资质)。它为上述观点及许多其他的观点提供了细节,并在文末列了参考文献来支持那些假说。

  综上所述,从个人角度而言,我不知道是否要接受这些替代解释,也不知晓神经可塑性本身是否能说明问题。不管怎样,它确实削弱了我先入为主的想法,我因此感到羞愧。

  你怎么看呢?

原文转载:http://tech.shaoqun.com/a/392787.html

跨境电商:https://www.ikjzd.com/

四海商舟:https://www.ikjzd.com/w/1516

extra:https://www.ikjzd.com/w/1736


来源:利维坦  导语/Introduction  2019年11月,《自然》杂志上发表了一篇论文,名为《没有大脑的生命:神经放射学和行为学证据表明,严重脑积水情况下,神经可塑性是维持大脑功能的必要条件》(Lifewithoutabrain:Neuroradiologicalandbehavioralevidenceofneuroplasticitynecessarytosustainbrainfu
贝贝母婴网:https://www.ikjzd.com/w/1321
法瑞儿:https://www.ikjzd.com/w/412
关键词分析工具:https://www.ikjzd.com/w/1968
亚马逊页面改版?listing主页可添加PDF:https://www.ikjzd.com/home/8573
【纯干货】亚马逊极限爆款操作技巧:https://www.ikjzd.com/home/126844
Wadi.com:https://www.ikjzd.com/w/768

根据污染寻找地外文明,是个好方法吗?|行星|恒星|地球


  撰文 | Bill Steigerwald

  翻译 | 耿淑娟

  审校 | 张和持

  近期,NASA发表的一项研究表明,假如我们附近的恒星系统中存在先进的地外文明,我们或许能够利用它自身的大气污染,对其进行探测。这项研究主要评估了一种大气污染物——二氧化氮。在地球上,这种气体主要由化石燃料燃烧产生,不过它也有一些非工业来源,例如一些生物学过程、闪电和火山喷发。

  "在地球上,大多数二氧化氮来自人类活动——比如汽车尾气和化石燃料发电厂,"NASA戈达德太空飞行中心的Ravi Kopparapu说,"在较低层大气中(距地面约10至15公里)的二氧化氮,绝大部分来自人类活动。因此,在宜居星球上观测到二氧化氮,或许能够说明该星球存在工业化文明。" Kopparapu是这项研究的第一作者,该论文已被《天体物理学杂志》接受。


  迄今为止,天文学家已经发现了4000多个系外行星。据我们所知,有些行星可能拥有适合生命存在的环境条件,在其中一些行星中,生命或许已经达到了科技文明的程度。由于其他恒星周围的行星(系外行星)过于遥远,科学家们无法通过发射航天器的方式,来寻找寻找它们的生命或文明迹象。因此,他们需要使用功能强大的望远镜来观察这些系外行星大气层内部的物质。

  一个生命标志的可能迹象是,大气由氧气与甲烷等气体组成。同样地,系外行星的科技标志物也可能是在地球上被视为污染的气体,这类气体(比如二氧化氮)是工业过程中的副产品。

  "其他一些研究已经将氯氟烃(CFC)作为一种可能的科技标志物。氯氟烃是一种工业产品,曾被广泛用作制冷剂,后来因为会导致臭氧层空洞而被淘汰。" 该论文的合作作者、蓝色大理石太空科学研究所的Jacob Haqq-Misra表示,"CFC也是一种强效温室气体,可从大气层获取额外热量,可以用于火星等其他行星的地球化改造。据我们所知,生物完全不会产生CFC,因此与二氧化氮相比,它是一种更明显的科技标志物。但是,它是非常特殊的人造化学品,在其他星球上可能并不普遍;而相比之下,二氧化氮则是任何燃烧过程的一般副产物。"

  在这项研究中,研究小组利用计算机建模预测二氧化氮污染产生的信号,是否可以被当前和未来的望远镜检测到。大气中的二氧化氮会大量吸收一定波长的可见光,这可以通过观察系外行星绕恒星运行时反射的光来检测。

  研究人员发现,对于一颗围绕类日恒星运行的类地行星,如果当地的文明产生了和地球相当数量的二氧化氮,那么使用未来NASA发射的大型可见光望远镜,我们就能在30光年左右的距离内观测约400小时,进而发现它。此观测时间虽然十分漫长,但并非史无前例,NASA的哈勃太空望远镜便花费了相似的时间进行著名的深空观测(Deep Field observations)。

  研究者们还发现,比太阳温度更低、更常见的恒星(如K和M型恒星)将产生更强且更易被检测到的二氧化氮信号。这是因为紫外线能够分解二氧化氮,而这些恒星产生的紫外线较少。多种类型的恒星也增加发现外星文明的机会。

  由于二氧化氮也可以由自然环境产生,因此将来科学家们必须细致地分析系外行星,判断是否还有其他物质会产生于一个技术发达的社会。该论文的共同作者、NASA戈达德太空飞行中心的 Giada Arney表示:"在地球上,约有76%的二氧化氮排放是由工业活动造成的。如果我们观察到另一颗行星上存在二氧化氮,那么将需要通过模型来估算非工业来源产生的最大二氧化氮排放量。而如果观察到的二氧化氮量超出了最大的排放量,则多余的二氧化氮可能产生于工业活动。但是,在寻找地外生命的过程中,总是存在假阳性的可能性,因此在未来的工作中,需要确保能够区分阳性和假阳性。"

  还有可能存在的情况是,行星的大气中存在云或气溶胶。云、气溶胶和二氧化氮吸收的光的波长相似,因此可能会导致假阳性。该研究团队计划使用更先进的模型来判断,是否能够利用云层的自然变化来对二者进行区分。在初步研究中,研究人员利用模型,将行星大气层假设为从地面到太空的多层空气柱。在大多数情况下,这是一个很好的假设,且能进行快速计算。但是行星是三维物体,而不是一维的空气柱。该小组在后续的研究中,将使用3D模型来验证比较这一初步结果的准确性。

原文转载:http://tech.shaoqun.com/a/392785.html

跨境电商:https://www.ikjzd.com/

败欧洲运费:https://www.ikjzd.com/w/1555

邮乐网:https://www.ikjzd.com/w/1776


撰文|BillSteigerwald  翻译|耿淑娟  审校|张和持  近期,NASA发表的一项研究表明,假如我们附近的恒星系统中存在先进的地外文明,我们或许能够利用它自身的大气污染,对其进行探测。这项研究主要评估了一种大气污染物——二氧化氮。在地球上,这种气体主要由化石燃料燃烧产生,不过它也有一些非工业来源,例如一些生物学过程、闪电和火山喷发。  "在地球上,大多数二氧化氮来自人类活动——比如汽
houzz:https://www.ikjzd.com/w/236
马莎:https://www.ikjzd.com/w/2385
中国邮政邮乐网:https://www.ikjzd.com/w/1776
口述:离婚后他搬空了家窗帘也没给我留(2/2):http://lady.shaoqun.com/m/a/45191.html
为什么我的产品老是审核不通过?Lazada产品审核拒绝原因:https://www.ikjzd.com/home/128841
三态速递:https://www.ikjzd.com/w/1981