[原创]FineUI秘密花园(二十一) — 表格之动态创建列

有时我们需要根据数据来动态创建表格列,怎么来做到这一点呢?本章会详细讲解。

 

动态创建的列

还是通过一个示例来看下如何在FineUI中动态创建表格列,示例的界面截图:

image

 

先来看下ASPX的标签定义:

   1:  <ext:Grid ID="Grid1" runat="server" Width="650px" EnableCheckBoxSelect="true" EnableRowNumber="true"
   2:      Title="表格(动态创建的列)">
   3:  </ext:Grid>

 

ASPX标签中没有定义任何列,所有列都是在后台定义的:

   1:  // 注意:动态创建的代码需要放置于Page_Init(不是Page_Load),这样每次构造页面时都会执行
   2:  protected void Page_Init(object sender, EventArgs e)
   3:  {
   4:      InitGrid();
   5:  }
   6:   
   7:  private void InitGrid()
   8:  {
   9:      FineUI.BoundField bf;
  10:   
  11:      bf = new FineUI.BoundField();
  12:      bf.DataField = "Id";
  13:      bf.DataFormatString = "{0}";
  14:      bf.HeaderText = "编号";
  15:      Grid1.Columns.Add(bf);
  16:   
  17:      bf = new FineUI.BoundField();
  18:      bf.DataField = "Name";
  19:      bf.DataFormatString = "{0}";
  20:      bf.HeaderText = "姓名";
  21:      Grid1.Columns.Add(bf);
  22:   
  23:      bf = new FineUI.BoundField();
  24:      bf.DataField = "EntranceYear";
  25:      bf.DataFormatString = "{0}";
  26:      bf.HeaderText = "入学年份";
  27:      Grid1.Columns.Add(bf);
  28:   
  29:      bf = new FineUI.BoundField();
  30:      bf.DataToolTipField = "Major";
  31:      bf.DataField = "Major";
  32:      bf.DataFormatString = "{0}";
  33:      bf.HeaderText = "所学专业";
  34:      bf.ExpandUnusedSpace = true;
  35:      Grid1.Columns.Add(bf);
  36:   
  37:      Grid1.DataKeyNames = new string[] { "Id", "Name" };
  38:  }
  39:   
  40:  protected void Page_Load(object sender, EventArgs e)
  41:  {
  42:      if (!IsPostBack)
  43:      {
  44:          LoadData();
  45:      }
  46:  }
  47:   
  48:  private void LoadData()
  49:  {
  50:      DataTable table = GetDataTable();
  51:   
  52:      Grid1.DataSource = table;
  53:      Grid1.DataBind();
  54:  }

整个代码结构非常清晰,分为页面的初始化阶段和页面的加载阶段。

在页面的初始化阶段:

  1. 创建一个新的FineUI.BoundField实例;
  2. 设置此实例的DataField、DataFormatString、HeaderText等属性;
  3. 将新创建的列添加到Grid1.Columns属性中。

 

页面的加载阶段就是绑定数据到表格,和之前的处理没有任何不同。

 

动态创建的模板列

模板列的动态创建有点复杂,我们先来看下创建好的模板列:

image

 

ASPX标签和上面例子一模一样,就不再赘述。我们来看下动态创建模板列的代码:

   1:  FineUI.TemplateField tf = new TemplateField();
   2:  tf.Width = Unit.Pixel(100);
   3:  tf.HeaderText = "性别(模板列)";
   4:  tf.ItemTemplate = new GenderTemplate();
   5:  Grid1.Columns.Add(tf);

 

这里的GenderTemplate是我们自己创建的类,这也是本例的关键点。

   1:  public class GenderTemplate : ITemplate
   2:  {
   3:      public void InstantiateIn(System.Web.UI.Control container)
   4:      {
   5:          AspNet.Label labGender = new AspNet.Label();
   6:          labGender.DataBinding += new EventHandler(labGender_DataBinding);
   7:          container.Controls.Add(labGender);
   8:      }
   9:   
  10:      private void labGender_DataBinding(object sender, EventArgs e)
  11:      {
  12:          AspNet.Label labGender = (AspNet.Label)sender;
  13:   
  14:          IDataItemContainer dataItemContainer = (IDataItemContainer)labGender.NamingContainer;
  15:   
  16:          int gender = Convert.ToInt32(((DataRowView)dataItemContainer.DataItem)["Gender"]);
  17:         
  18:          labGender.Text = (gender == 1) ? "男" : "女";
  19:      }
  20:  }

GenderTemplate实现了ITemplate接口,其中InstantiateIn在需要初始化模板中控件时被调用:

  1. 创建一个Asp.Net的Label控件实例 (AspNet.Label labGender = new AspNet.Label());
  2. 设置数据绑定处理函数(labGender.DataBinding += new EventHandler(labGender_DataBinding));
  3. 将此Label实例添加到模板容器中(container.Controls.Add(labGender))。

 

之后,在对Label进行数据绑定时:

  1. 首先得到当前Label实例,也即是sender对象;
  2. 获取Label的命名容器,此容器实现了IDataItemContainer接口;
  3. 将此接口的DataItem强制转换为DataRowView,因为数据源是DataTable;
  4. 根据数据源的值设置Label的值。

 

上面的两个示例,我们都把动态创建控件的代码当时Page_Init函数中,这是为什么呢?

要想明白其中的道理,我们还是要从Asp.Net中动态添加控件的原理说起。

 

太棒了太棒了太棒了

学习Asp.Net的视图状态和生命周期

这个话题比较深入,也不大容易理解,建议大家在阅读本节之前详细了解Asp.Net的视图状态和页面的生命周期,下面是两个非常经典的参考文章(本节的部分图片和文字都来自这两篇文章):

  1. Understanding ASP.NET View State
  2. 创建动态数据输入用户界面

 

Asp.Net页面的生命周期

从上图可以看出,Asp.Net页面的生命周期分为如下几个阶段:

  1. 实例化阶段:根据ASPX标签定义的静态结构创建控件的层次结构,并会调用页面的Page_Init事件处理函数。
  2. 加载视图状态阶段(仅回发):将VIEWSTATE中发现的视图状态数据恢复到控件的层次结构中。
  3. 加载回发数据阶段(仅回发):将回发的表单数据恢复到控件的层次结构中,如果表单控件的数据发生变化,还有可能在第5个阶段触发相应的事件。
  4. 加载阶段:此时控件的层次结构已经创建完毕,并且控件的状态已经从视图数据和回发数据中回发,此时可以访问所有的控件属性,并会调用页面的Page_Load事件处理函数。
  5. 触发回发事件(仅回发)阶段:触发回发事件,比如按钮的点击事件、下拉列表的选中项改变事件。
  6. 保存视图状态阶段:保存所有控件的视图状态。
  7. 渲染阶段:将所有页面控件渲染为HTML代码。

上面的这七个阶段是每个Asp.Net开发人员都应该熟悉和掌握的,它可以帮助我们理解页面中Page_Load和事件处理函数的逻辑关系。

 

注意:上述处理过程不管是在页面第一次加载还是在页面回发,都会发生。理解这一点非常重要!

 

动态添加控件的两种模式

动态添加控件需要在加载视图状态和加载回发数据之前进行,因为我们需要能够在添加控件之后恢复这些数据。所以这个阶段就对应了Page_Init处理函数,这也就是为什么上面两个例子都在此函数中动态添加控件。

 

但是由于在初始化阶段时,视图状态和回发数据还没有恢复,因此此时无法访问存储在视图状态或者回发数据中的控件属性。所以还有一个常用的模式是在Page_Init中添加控件,在Page_Load中为动态创建的控件设置默认值。

 

下面两个示例分别展示了动态添加控件的两种模式。

动态添加控件模式一:

   1:  protected void Page_Init(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      lab.Text = "Label1";
   6:   
   7:      Form.Controls.Add(lab);
   8:  }
   9:   
  10:  protected void Page_Load(object sender, EventArgs e)
  11:  {
  12:      
  13:  }

 

动态添加控件模式二:

   1:  protected void Page_Init(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:   
   6:      Form.Controls.Add(lab);
   7:  }
   8:   
   9:  protected void Page_Load(object sender, EventArgs e)
  10:  {
  11:      if (!IsPostBack)
  12:      {
  13:          AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label;
  14:          lab.Text = "Label1";
  15:      }
  16:  }

第二种模式是在初始化阶段添加动态控件,然后在加载阶段(!IsPostBack)设置控件的默认值。

 

 

 

 

错误使用动态添加控件的例子一

你可能会想上例中,为什么要将设置控件默认值的代码放在 !IsPostBack 逻辑块中,下面就来看下不放在!IsPostBack 逻辑块中的例子。

首先看下ASPX标签结构:

   1:  <form id="form1" runat="server">
   2:  <asp:Button ID="Button1" Text="Change Text" OnClick="Button1_Click" runat="server" />
   3:  <asp:Button ID="Button2" Text="Empty Post" runat="server" />
   4:  <br />
   5:  </form>

再看下后台的初始化代码:

   1:  protected void Page_Init(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:   
   6:      Form.Controls.Add(lab);
   7:  }
   8:   
   9:  protected void Page_Load(object sender, EventArgs e)
  10:  {
  11:      AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label;
  12:      lab.Text = "Label1";
  13:  }
  14:   
  15:   
  16:  protected void Button1_Click(object sender, EventArgs e)
  17:  {
  18:      AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label;
  19:      lab.Text = "Changed Label1";
  20:  }

按如下步骤操作:

  1. 第一次打开页面,显示的文本是 Label1;
  2. 点击“Change Text”按钮,显示的文本是 Changed Label1;
  3. 点击“Empty Post”按钮,显示的文本是 Label1。

这就不对了,点击“Empty Post”按钮时显示的文本也应该是 Changed Label1,但是上例中文本控件的视图状态没有保持,这是为什么呢?

原因也很简单,当用户进行第三步操作(即点击“Empty Post”按钮):

  1. 在初始化阶段(Page_Init),添加了动态控件Label1;
  2. 根据页面的生命周期,之后进行的是加载视图状态(LoadViewState),此时动态控件Label1的文本是 Changed Label1;
  3. 加载视图状态之后就开始跟踪视图状态的变化;
  4. 在加载阶段(Page_Load),跟踪到了控件属性值的变化,Label1的值就又从Chenged Label1变成了Label1。

 

关键点:当控件完成加载视图状态阶段后,就会立即开始跟踪其视图状态的改变,之后任何对其属性的改变都会影响最终的控件视图状态。

理解这一点非常重要,如果你尚未理解这句话的意思,请多读几遍,再多读几遍,这句话同时会影响后面介绍的另外两种动态添加控件的模式。

 

如果你能理解上面提到的过程,说明你已经掌握了Asp.Net的页面生命周期和ViewState的加载过程了。

 

动态添加控件的另外两种模式

除了在初始化阶段动态添加控件外,还可以再加载阶段添加控件。这是因为当把一个控件添加到另一个控件的Controls集合时,所添加的控件的生命周期会立即同步到父控件的生命周期。比如,如果父控件处于初始化阶段,则会触发所添加控件的初始化事件;如果父控件处于加载阶段,则会触发所添加控件的的初始化事件、加载视图事件、加载回发数据事件以及加载事件。

 

由此,我们就有了另外两种动态添加控件的模式:

动态添加控件模式三:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      lab.Text = "Label1";
   6:      Form.Controls.Add(lab);
   7:  }

 

对于这一种模式,你是否有这样的疑问?:

如果此标签的Text属性在某次Ajax回发时改变了,那么下次Ajax回发时,创建此标签并赋默认值会不会覆盖恢复的视图状态呢(因为此时已经过了加载视图状态阶段)?

其实不会这样的,虽然在Page_Load已经过了加载视图状态阶段,但是由于此标签控件尚未添加到控件层次结构中,所以尚未经历加载视图状态阶段,只有在Controls.Add之后才会经历标签控件的初始化阶段、加载视图状态阶段、加载回发数据阶段和加载阶段。

 

下面通过一个例子说明,首先看下ASPX标签结构:

   1:  <form id="form1" runat="server">
   2:  <asp:Button ID="Button1" Text="Change Text" OnClick="Button1_Click" runat="server" />
   3:  <asp:Button ID="Button2" Text="Empty Post" runat="server" />
   4:  <br />
   5:  </form>

后台代码:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      lab.Text = "Label1";
   6:      Form.Controls.AddAt(label2Index, lab);
   7:  }
   8:   
   9:  protected void Button1_Click(object sender, EventArgs e)
  10:  {
  11:      AspNet.Label lab = Form.FindControl("Label1") as AspNet.Label;
  12:      lab.Text = "Changed Label1";
  13:  }

进行如下操作:

  1. 第一次打开页面,显示的文本是 Label1;
  2. 点击“Change Text”按钮,显示的文本是 Changed Label1;
  3. 在Page_Load中设置断点,点击“Empty Post”按钮,观察标签的Text属性如下所示。

 

在执行Controls.Add之前,文本值还是Label1:

image

 

在执行Controls.Add之后,文本值从视图状态恢复,变成了 Changed Label1:

image

 

 

动态添加控件模式四:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      
   6:      Form.Controls.Add(lab);
   7:   
   8:      if (!IsPostBack)
   9:      {
  10:          lab.Text = "Label1";
  11:      }
  12:  }

 

错误使用动态添加控件的例子二

如果你认为自己已经掌握了动态添加控件的原理,不妨来看下面这个错误的例子,看能否指出其中错误的关键。

先来看下ASPX标签结构:

   1:  <form id="form1" runat="server">
   2:  <asp:Button ID="Button2" Text="Empty Post" runat="server" />
   3:  <br />
   4:  </form>

 

在看后台初始化代码:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      if (!IsPostBack)
   6:      {
   7:          lab.Text = "Label1";
   8:      }
   9:   
  10:      Form.Controls.Add(lab);
  11:  }

是不是和动态添加控件模式四比较类似,不过这里的用法却是错误的,你能看出问题所在吗?

 

来运行一把:

  1. 第一次加载页面,显示的文本是Label1;
  2. 点击“Empty Post”按钮,显示的文本为空(这就不对了,应该还是Label1)。

 

为什么会出现这种情况?我们来分析一下:

  • 第一次加载页面时,设置了文本标签的默认值,然后添加到控件层次结构中;
  • 添加到控件层次结构后,即开始跟踪视图状态的变化,但是此标签的Text属性并没改变,所以最终没有保存到视图状态中;
  • 点击按钮回发时,文本标签的默认值为空,然后添加到控件层次结构中,在加载视图状态阶段没有发现文本标签的视图,所以最终显示为空。

 

那为什么模式四是正确的呢?

简单来说,修改标签的Text属性时已经在跟踪视图状态的改变了,所以这个修改的值被保存了下来;下次回发时又将此值从视图中恢复了出来。

 

 

错误使用动态添加控件的例子三

如果上面的都掌握了,再来看下面这个错误的示例,ASPX标签结构如下:

   1:  <form id="form1" runat="server">
   2:  <asp:Button ID="Button2" Text="Empty Post" runat="server" />
   3:  <br />
   4:  <asp:Label ID="Label2" Text="Label2" runat="server"></asp:Label>
   5:  </form>

后台初始化代码如下:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      AspNet.Label lab = new AspNet.Label();
   4:      lab.ID = "Label1";
   5:      lab.Text = "Label1";
   6:      
   7:      int label2Index = Form.Controls.IndexOf(Label2);
   8:   
   9:      Form.Controls.AddAt(label2Index, lab);
  10:   
  11:   
  12:      if (!IsPostBack)
  13:      {
  14:          lab.Text = "Changed Label1";
  15:      }
  16:  }

这段代码进行了如下处理:

  1. 新创建一个标签实例Label1,并设置默认值Label1;
  2. 找到页面上现有标签Label2在父控件中的索引号;
  3. 将新创建的Label1控件插入Label2所在的位置,也即是将Label2向后移动一个位置;
  4. 在页面第一次加载时更改新创建标签Label1的文本为Changed Label1。

 

我们来看下页面第一个加载的显示:

image

一切正常,被改变文本值的Label1位于Label2的前面。

 

然后点击“Empty Post”按钮,会出现如下情况:

image

为什么本应该保持状态的Label2,现在的值却变成了Changed Label1?

 

根本原因是Asp.Net保存保存视图状态的方式,是按照控件出现的顺序保存的,当然恢复也是按照顺序进行的,关于这一特性,我有专门一篇文章详细阐述。

 

总之,简单两句话:

  1. 在Page_Load中动态添加控件时,不要改变现有控件的顺序;
  2. 如果想改变现有控件的顺序,可以再Page_Init中进行添加。

 

 

或者简单一句话:在ASP.NET中,所有动态添加控件的代码都要放到 Page_Init 中进行!

 

 

小结

其实在FineUI中编写动态创建的表格列非常简单,但是要想理解其中原理,就不那么简单了。本篇文章的最后一节详细描述了动态创建控件的原理,也希望大家能够细细品味,深入了解Asp.Net的内部运行机制。

下一篇文章我们会详细讲解如何从表格导出Excel文件。

 

注:《FineUI秘密花园》系列文章由三生石上原创,博客园首发,转载请注明出处。文章目录 官方论坛

转载于:https://www.cnblogs.com/sanshi/archive/2012/11/19/2776672.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Hands On ML] 8. 降维

文章目录1. 降维方法1.1 投影1.2 流行学习2. 降维技术2.1 PCA2.2 增量PCA2.3 随机PCA2.4 核PCA2.5. 调参2.6 LLE2.7 其他方法本文为《机器学习实战&#xff1a;基于Scikit-Learn和TensorFlow》的读书笔记。 中文翻译参考 特征维度太大&#xff0c;降维加速训练能筛掉一些噪声和…

LeetCode 776. 拆分二叉搜索树(DFS)*

文章目录1. 题目2. 解题1. 题目 给你一棵二叉搜索树&#xff08;BST&#xff09;、它的根结点 root 以及目标值 V。 请将该树按要求拆分为两个子树&#xff1a;其中一个子树结点的值都必须小于等于给定的目标值 V&#xff1b;另一个子树结点的值都必须大于目标值 V&#xff1…

变压器绕组降低邻近效应_了解高频变压器设计基础(2)

单片开关电源高频变压器的设计要点高频变压器是单片开关电源的核心部件&#xff0c;鉴于这种高频变压器在设计上有其特殊性&#xff0c;为此专门阐述降低其损耗及抑制音频噪声的方法&#xff0c;可供高频变压器设计人员参考。单片开关电源集成电路具有高集成度、高性价比、最简…

Python-jieba分词学习及应用

文章目录基础添加自定义词典实战基础 jieba.cut 方法接受三个输入参数: 需要分词的字符串&#xff1b;cut_all 参数用来控制是否采用全模式&#xff1b;HMM 参数用来控制是否使用 HMM 模型jieba.cut_for_search 方法接受两个参数&#xff1a;需要分词的字符串&#xff1b;是否…

LeetCode 302. 包含全部黑色像素的最小矩形(BFS)

文章目录1. 题目2. 解题1. 题目 图片在计算机处理中往往是使用二维矩阵来表示的。 假设&#xff0c;这里我们用的是一张黑白的图片&#xff0c;那么 0 代表白色像素&#xff0c;1 代表黑色像素。 其中黑色的像素他们相互连接&#xff0c;也就是说&#xff0c;图片中只会有一…

蓝色三角_叶子长得像韭菜,花朵开得像个糖三角的鸢尾,用这3个方法拍摄它...

女孩子们小时候都跳皮筋。有一段口诀&#xff0c;里面有一句“马兰开花二十一”……我虽然皮筋没少跳&#xff0c;但是对于马兰花&#xff0c;却也是只闻其名&#xff0c;未见其身。后来&#xff0c;我在户外拍风光、拍花卉。在草丛里看到三片细长花瓣组成的的蓝色小花&#xf…

LeetCode 1063. 有效子数组的数目(单调栈)

文章目录1. 题目2. 解题1. 题目 给定一个整数数组 A&#xff0c;返回满足下面条件的 非空、连续 子数组的数目&#xff1a; 子数组中&#xff0c;最左侧的元素不大于其他元素。 示例 1&#xff1a; 输入&#xff1a;[1,4,2,5,3] 输出&#xff1a;11 解释&#xff1a;有 11 个…

springboot 多了8小时_日本人不明白:中国的奶茶有多好喝,值得排队8小时去买?...

日本人不明白&#xff1a;中国的奶茶有多好喝&#xff0c;值得排队8小时去买&#xff1f;最近有许多的网红奶茶店兴起&#xff0c;尤其是在冬季&#xff0c;加料十足的热奶茶就成为了年轻人的心头之好&#xff0c;就拿最近在武汉新开的首家茶颜悦色来说&#xff0c;每天的队伍都…

将整个表单设置为只读_如何将独立网站设置为制作中,阻止搜索引擎收录网站页面?...

独立网站设置为制作中当网站未完成状态时&#xff0c;可能不希望除管理员以外的人看到未完成的页面时&#xff0c;如何操作可以将独立网站设置为制作中&#xff0c;并阻止搜索引擎收录网站页面呢&#xff1f;可按照以下步骤进行操作&#xff1b;将网站设置为制作中网站制作中设…

LeetCode 361. 轰炸敌人(前缀和DP)

文章目录1. 题目2. 解题1. 题目 想象一下炸弹人游戏&#xff0c;在你面前有一个二维的网格来表示地图&#xff0c;网格中的格子分别被以下三种符号占据&#xff1a; W 表示一堵墙 E 表示一个敌人 0&#xff08;数字 0&#xff09;表示一个空位请你计算一个炸弹最多能炸多少敌…

led拼接屏报价_液晶拼接屏与led显示屏的区别在哪?

在目前的大屏显示产品中&#xff0c;液晶拼接屏和led显示屏是两种比较普遍的产品&#xff0c;拼接大屏是通过单个液晶拼接单元拼接而成的显示大屏&#xff0c;而led显示屏则是通过发光二极管组成密集点阵组成图像显示&#xff0c;我们通常听到的P1、P2代表的是像素点距离&#…

LeetCode 356. 直线镜像

文章目录1. 题目2. 解题1. 题目 在一个二维平面空间中&#xff0c;给你 n 个点的坐标。 问&#xff0c;是否能找出一条平行于 y 轴的直线&#xff0c;让这些点关于这条直线成镜像排布&#xff1f; 示例 1&#xff1a; 输入: [[1,1],[-1,1]] 输出: true示例 2&#xff1a; 输入…

使用DispatcherTimer计时器

《银光志--Silverlight 3.0开发详解与最佳实践》第3章XAML与Silverlight编程内功&#xff0c;通过本章的学习&#xff0c;相信你会对Silverlight编程模型、XAML、事件处理&#xff0c;以及LINQ查询语言有了一个比较全面的了解&#xff0c;在本章的示例中应用的都是一些基本的XA…

静物摄影用光技巧_室内人像摄影想要拍好,这3种用光技巧你了解吗?

选择靠近窗户的位置在室内可以首先考虑在靠近窗户的位置进行拍摄&#xff0c;因为窗户边上尤其是朝北的窗户会有非常柔和的散射光&#xff0c;当投射进窗户的是直射光线时&#xff0c;摄影者还可以拉上一层很薄的窗帘来缓解一下光线的强度&#xff0c;在靠近窗户的位置&#xf…

LeetCode 660. 移除 9(9进制)

文章目录1. 题目2. 解题1. 题目 从 1 开始&#xff0c;移除所有包含数字 9 的所有整数&#xff0c;例如 9&#xff0c;19&#xff0c;29&#xff0c;…… 这样就获得了一个新的整数数列&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&…

postman怎么导出测试用例_利用Charles抓包巧转接口自动化测试用例

在前面的文章中&#xff0c;也有介绍类似的工具的。例如&#xff1a;一键将接口请求转为测试用例介绍了开源的mitmproxy录制转化为接口测试用例&#xff0c;postman接口用例转化为python自动化测试用例 文章记录了如何把postman的测试用例转化为python的接口自动化的测试用例&a…

LeetCode 1236. 网络爬虫(BFS/DFS)

文章目录1. 题目2. 解题2.1 BFS2.2 DFS1. 题目 给定一个链接 startUrl 和一个接口 HtmlParser &#xff0c;请你实现一个网络爬虫&#xff0c;以实现爬取同 startUrl 拥有相同 域名标签 的全部链接。该爬虫得到的全部链接可以 任何顺序 返回结果。 你的网络爬虫应当按照如下模…

启动不起来_国产开源工具:U盘启动工具Ventoy v1.0.29发布——墨涩网

Ventoy是一个制作可启动U盘的开源工具。有了Ventoy你就无需反复地格式化U盘&#xff0c;你只需要把ISO文件拷贝到U盘里面就可以启动了&#xff0c;无需其他操作。你可以一次性拷贝很多个不同类型的ISO文件&#xff0c;在启动时Ventoy会显示一个菜单来选择。 无差异支持Legacy B…

众多Android 开源项目再次推荐,学习不可错过

FBReaderJ FBReaderJ用于Android平台的电子书阅读器&#xff0c;它支持多种电子书籍格式包括&#xff1a;oeb、ePub和fb2。此外还支持直接读取zip、tar和gzip等压缩文档。项目地址&#xff1a;http://www.fbreader.org/FBReaderJ/Angle Angle是一款专为Android平台设计的&#…

LeetCode 1231. 分享巧克力(极小极大化 二分查找)

文章目录1. 题目2. 解题1. 题目 你有一大块巧克力&#xff0c;它由一些甜度不完全相同的小块组成。我们用数组 sweetness 来表示每一小块的甜度。 你打算和 K 名朋友一起分享这块巧克力&#xff0c;所以你需要将切割 K 次才能得到 K1 块&#xff0c;每一块都由一些 连续 的小…