ASP.NET学习笔记[12] - Gridview里的下拉框筛选效果_asp.net gridview筛选-程序员宅基地

技术标签: filter  筛选  类似Excel  .NET  js  下拉框  gridview  

#一、前言#

很多第三方插件实现了这个功能,但不是我想要的那种像Excel表头一点就展开筛选面板的效果(很多用的是文本框输入filter查询条件),干脆自己动手丰衣足食吧。当初觉得太复杂,拖了很久,直到真的实现了,回头看看挺不可思议的。

#二、概述#

ASP.NET页面上我们显示数据表格一般用GridView控件,有时GridView数据行数很多,我想用一个类似Excel里的筛选功能来检索数据,如下图:

Excel筛选功能

下图是我实现的效果,是不是很像Excel里的筛选功能。

我实现的效果图

#三、基本思路#

GridView列可以通过TemplateField实现用户自定义列模板,我们用ItemTemplate比较多,但是它也有HeaderTemplate,如果在里面放一个dropdownlist来实现下拉框效果,就可以把当前这个字段所有的值按distinct方式查询,结果集绑回dropdownlist控件,为dropdownlist定义一个响应事件,完成选择后触发该事件重新查询数据集,dropdownlist中的选项作为sql查询条件,动态组装出新的sql语句,得到新数据集重新绑定回GridView。

#四、核心控件 MultipleDropdownList#

##4.1 为啥需要MultipleDropdownList ##
首先我们需要一个复选下拉框控件,网上有很多大牛写好的,但是没有能直接用在本例的,多选结束后,需要一个动作来提交选项,使用button是很自然的选择,于是至少需要两个按钮:确定和取消,然后我又增加了一个取消筛选按钮,可以方便地将当前列中所有选项恢复到默认状态(全选状态)。
##4.2 MultipleDropdownList 的来历##
目前大家看到的截图中的控件是我搜索出一个大牛的作品然后改造了一下,增加了三个按钮,修改了响应事件的处理方法,需要注意的是,这个控件只能在gridview做筛选功能时使用,如果只是想普通地使用复选下拉框,直接用网上的原版就可以了。

原文地址:http://blog.csdn.net/bclz_vs/article/details/7317266

##4.3 MultipleDropdownList 部分细节说明##
MultipleDropdownList是CompositeControl类型控件,代码不粘贴了,下载链接在文章最后,仅就一些需要说明的地方解释一下。

###4.3.1 MultipleDropdownList 类文件###

private CheckBoxList _checkBoxes;
private Button _btnsOK;          //确定按钮 
//private Button _btnsCL;        //取消按钮  
private Button _btnsRevoke;      //取消筛选按钮   
private TextBox _textBox;
private static ListItem _selectAllItem = new ListItem("全选", "___selectAll___");

整个复合控件是由一个CheckBoxList两个button一个textbox组合而成,textbox就是在页面上呈现的控件收起样式,当展开时,向下延伸出的div里就是checkboxlist和几个button组成成的筛选面板,其实还有一个取消按钮,这个按钮后来我改成了纯html按钮,不再使用服务器控件,取消按钮不需要回发信息给服务器。
这里写图片描述

###4.3.2 重写DataSource###

public Object DataSource
{
    get 
    {
        if (ViewState["_dataSource"] != null)
        {
            DataTable stoveTable = (DataTable)ViewState["_dataSource"];
            DataRow dataRow = stoveTable.NewRow();
            dataRow[0] = "全选";
            stoveTable.Rows.InsertAt(dataRow, 0);
            ViewState["_dataSource"] = stoveTable;
        }
        return ViewState["_dataSource"];
    }
    set { ViewState["_dataSource"] = value; }
}

这样写的目的就是为了在选项列表自动加上“全选”项,不需要用户自己写代码实现给下拉框增加“全选”项。不过这样写DataSource只能接收datatable类型的数据,之前大牛写的还可以接收list类型,有得有失吧。

###4.3.3 OnConfirm事件###

为复合控件增加OnConfirm事件,在点击确定按钮时触发这个事件,自定义控件的事件冒泡我参考了这位大牛的文章。
原文:http://www.cnblogs.com/yanyangtian/archive/2008/08/25/1275741.html

在冒泡事件OnBubbleEvent内判断命令是Confirm还是Revoke,这两个命令分别来自确定按钮和取消筛选按钮,如果是取消筛选,则清空所选也就是默认目标列恢复到全选状态。可以理解为,这里的主要工作就是根据点击的按钮正确的计算和维持checkboxlist里选项的勾选状态。
###4.3.4 GetDivWidth方法###
GetDivWidth()的主要作用是计算展开div的宽度,遍历计算所有选项的字符长度,找到最长的选项的字符,在其长度的基础上加上滚动条的宽度和两边留白的距离,这样才能让展开的div面板好看,且选项不会因为宽度不够而换行挤在一起,这里偷懒用for循环遍历,效率理论上不忍直视,实际用起来还行。
###4.3.5 几个override的方法###
CreateChildControls() 创建组合控件中的子控件对象
RenderContents(HtmlTextWriter writer) 编写将在客户端呈现的内容
Render方法是将服务器控件内容发送到提供的HtmlTextWriter 对象,此对象编写将在客户端呈现的内容,或者调用编写内容的方法例如本例RenderContents
OnInit方法,在所有控件都已初始化且已应用所有外观设置后引发。使用该事件来读取或初始化控件属性。不需要你手动调用,在执行完PreInit后便会自动执行。Page_Load其实是响应页面的Load事件,它在OnInit后面执行! 每个页面都有OnInit 方法,(你没有重写不代表它不存在),而Page_Load是可以没有的,你可以删除页面中的Page_Load
###4.3.6 js文件和css文件###
js文件内的主要内容就是实现div的展开和复选框的勾选功能,作为嵌入资源即可。

#五、实现方法(前台页面需要做的事)#

##第一步:在aspx页面添加引用##

<%@ Register Assembly="DevControl" Namespace="DevControl" TagPrefix="Dev" %>

##第二步:添加js和css引用##

<link href="../css/multipledropdownList/MultipleDropdownList.css" type="text/css" rel="stylesheet" />
<script src="../css/multipledropdownList/jquery-1.6.1.js" type="text/javascript"></script>

后来我把js和css都一起封装到dll里面了,如果你直接添加dll应用,就不需要再添加js和css;如果你直接用源代码编译,那还是需要引用。

##第三步:添加js引用代码段##

<script type="text/javascript" language="javascript">  Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);      Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
        function BeginRequestHandler(sender, args) {
            var $mutipleDropdownLists = $('span.__MultipleDropdownList__');
            $mutipleDropdownLists.each(function () {
                multipleDropdownList(this);
            });
            var $BtnCancel = $('span.__BtnCancel__');
            $BtnCancel.each(function () {
                hiddenDiv(this);
            });
        }
        function EndRequestHandler(sender, args) {
            var $mutipleDropdownLists = $('span.__MultipleDropdownList__');
            $mutipleDropdownLists.each(function () {
                multipleDropdownList(this);
            });
            var $BtnCancel = $('span.__BtnCancel__');
            $BtnCancel.each(function () {
                hiddenDiv(this);
            });
        }

和第二步一样如果直接用dll就不需要了。

##第四步:将控件放入GridView的HeaderTemplate##

<asp:GridView ID="GridView1" runat="server" Width="100%" OnRowCommand="GridView1_RowCommand" AutoGenerateColumns="False"                                            OnRowDataBound="GridView1_RowDataBound" OnRowDeleting="GridView1_RowDeleting"                                        OnPreRender="GridView1_PreRender" OnDataBound="GridView1_DataBound">
<Columns>                                                  	<asp:TemplateField HeaderText="材料编码">
   <HeaderTemplate>
   <Dev:MultipleDropdownList ID="DropDownListHeadPartNo" runat="server" OnConfirmClick="DropDownListHead_SelectedIndexChanged"
Width="100%" />
   </HeaderTemplate>
   <ItemTemplate>
   <asp:Label ID="Label1" runat="server" Text='<%# Bind("材料编码") %>'>
   </asp:Label>
   </ItemTemplate>
   <ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
。。。(若干列)
</Columns>
</asp:GridView>
注意:代码中的若干列是省略掉的代码,gridview中定义了若干列,重复的代码不在这里占用篇幅

#六、实现方法(后台代码需要做的事)#

##第一步:定义需要用到的常量(全选标志)##

const string SelectAllListItemText = "SelectAll";   //全选标志位

##第二步:第一次sql查询处理事件##

第一次查询datatable并显示到gridview上时需要为每一个参加筛选的字段准备一个viewstate,并赋值SelectAllListItemText。说白了就是给每个筛选列一个初始值,默认初始状态是全选。

用viewstate当缓存是最快的,用别的也可以,性能问题大家按需考虑,我的项目用viewstate没啥大问题
//执行查询动作的事件
protected void btnQueryStore_Click(object sender, EventArgs e)
{
    if (ddlGType.SelectedValue == "-请选择材料类别-")
    {
        ScriptManager.RegisterStartupScript(this, this.GetType(), "key", "alert('请选择材料类别')", true);
    }
    else
    {
        ViewState["ddlpartno"] = SelectAllListItemText; 
        ViewState["ddlname"] = SelectAllListItemText; 
        ViewState["ddlsize1"] = SelectAllListItemText; 
        ViewState["ddlsize2"] = SelectAllListItemText; 
        ViewState["ddlsch1"] = SelectAllListItemText; 
        ViewState["ddlsch2"] = SelectAllListItemText; 
        ViewState["ddlend"] = SelectAllListItemText; 
        ViewState["ddlclass"] = SelectAllListItemText; 
        ViewState["ddlstulen"] = SelectAllListItemText; 
        ViewState["ddlmaterial"] = SelectAllListItemText; 
        ViewState["ddlstd"] = SelectAllListItemText; 
        ViewState["ddltagnumber"] = SelectAllListItemText; 
        ViewState["ddlaera"] = SelectAllListItemText; 

        DataTable dt = 根据业务逻辑查询数据集,返回datatable
        GridView1.DataSource = dt;
        GridView1.DataBind();
        ViewState["dt"] = dt;
    }
}

注意:此时根据业务逻辑查询数据集时是不带筛选过滤条件的

##第三步: GridView的RowDataBound事件##
第一次将datatable绑定到gridview时,筛选列里的选项要都绑好,没选项怎么筛呢

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.Header)
    {
        MultipleDropdownList ddlpartNo = (MultipleDropdownList)e.Row.FindControl("DropDownListHeadPartNo");  //材料编码
        。。。。。。若干列相同的处理

        MultipleDropdownList ddlaera = (MultipleDropdownList)e.Row.FindControl("DropDownListHeadAera");      //主项号

        string projectId = HiddenField_ProjectId.Value;
        //绑定材料编码
        ddlpartNo.DataSource = MakeNewStoreColumn.BindGVHeadPartNo(projectId,ddlGType.SelectedValue);
        ddlpartNo.DataTextField = "材料编码";
        ddlpartNo.DataValueField = "材料编码";
        ddlpartNo.SelectedValuesJoined = ViewState["ddlpartno"].ToString();
        ddlpartNo.DataBind();
        ddlpartNo.Text = "材料编码";

        //绑定材料名称
        ddlpartName.DataSource = MakeNewStoreColumn.BindGVHeaditemNo(projectId, ddlGType.SelectedValue);
        ddlpartName.DataTextField = "材料名称";
        ddlpartName.DataValueField = "材料名称";
        ddlpartName.SelectedValuesJoined = ViewState["ddlname"].ToString();
        ddlpartName.DataBind();
        ddlpartName.Text = "材料名称";

。。。。。。若干列相同的处理

        //绑定主项号
        ddlaera.DataSource = MakeNewStoreColumn.BindGVHeadAera(projectId, ddlGType.SelectedValue);
        ddlaera.DataTextField = "主项号";
        ddlaera.DataValueField = "主项号";
        ddlaera.SelectedValuesJoined = ViewState["ddlaera"].ToString();
        ddlaera.DataBind();
        ddlaera.Text = "主项号";       
    }
}

##第四步: 实现BindGVHead方法##
该方法就是去查询目标字段的值有哪些选项,一个distinct查询,然后返回一个datatable,绑到当前的MultipleDropdownList上。

有几个可筛选的列,就有几个这样的方法,每个方法用来查各自列的不重复值数据集
static public DataTable BindGVHeadPartNo(string projectId,string GType)
{
    DataTable dt = new DataTable();

    string sql = "SELECT DISTINCT 语句 " +
                 "ORDER BY 语句";
    SqlParameter[] prams = new SqlParameter[2];
    prams[0] = new SqlParameter("@projectId",SqlDbType.BigInt);
    prams[0].Value = projectId; //业务参数
    prams[1] = new SqlParameter("@GType",SqlDbType.VarChar,50);
    prams[1].Value = GType;  //业务参数
    dt = 执行查询动作返回datatable (sql, prams).Tables[0];
    return dt;
}

##第五步: 实现DropDownListHead_SelectedIndexChanged方法##
实现DropDownListHead_SelectedIndexChanged方法,这是核心部分

protected void DropDownListHead_SelectedIndexChanged(object sender, EventArgs e)
{
    MultipleDropdownList ddlist = (MultipleDropdownList)sender;  //获取所有字段head的状态

    /*******************************
     * 每个if块 
     * 第一步:判断IsSelectAll属性,如果是返回"-all-",如果不是进入else,开始第二步
     * 第二步:判断SelectedValuesJoined属性是否为""(空值),如果是返回"",如果不是返回SelectedValuesJoined
     */

    if (ddlist.ID == "DropDownListHeadPartNo")
    {
        if (ddlist.SelectedValuesJoined == null)
        {
            ViewState["ddlpartno"] = SelectAllListItemText;
        }
        else if (ddlist.SelectedValuesJoined == String.Empty)
        {
            ViewState["ddlpartno"] = "なにぬ";   //说明没有选任何项,此时给一个奇怪的字符(这里用日文)作为查询条件
        }
        else
        {
            ViewState["ddlpartno"] = ddlist.SelectedValuesJoined;
        }

    }
      
。。。。。。若干列相同的处理        

    string AndCondition = String.Empty;     //Sql字符串缓存,一个字段查询条件的or部分总和
    ArrayList sqlList = new ArrayList();

    sqlList.Clear();

    //组装sql后半部分(查询条件)
    //[材料编码]。。。。若干字段
    AndCondition = GetAndConditionString("材料编码", ViewState["ddlpartno"].ToString());    //【材料编码】查询条件的or部分总和
    if (AndCondition != String.Empty)
    { sqlList.Add(AndCondition); }

。。。。。。若干列相同处理

    //sql语句,组装AND条件部分
    HiddenField_Filter.Value = String.Empty;

    if (sqlList.Count == 0)   //如果没有查询条件
    { HiddenField_Filter.Value = String.Empty; }
    else   //如果有查询条件
    {
        string[] sqlOrPhrase = new string[sqlList.Count];
        sqlList.CopyTo(sqlOrPhrase);
        for (int i = 0; i < sqlOrPhrase.Length; i++)
        {
            HiddenField_Filter.Value = HiddenField_Filter.Value + " AND (" + sqlOrPhrase[i] + ")";
        }
    }

    StringBuilder sqls = new StringBuilder();

    //这里是拼装sql语句的关键地方:
    //该sql语句就是你之前查datatable的语句,只不过加上了某些字段的筛选项作为过滤条件要把这个条件拼接成新的sql语句
    sqls.Append("原来的select语句");
    sqls.Append("WHERE子句 "); //注意最后要跟一个空格
    sqls.Append(HiddenField_Filter.Value);  //这个是用GetAndConditionString方法加for循环拼接出来的sql语句过滤条件部分
    sqls.Append(" ORDER BY 子句");

    ViewState["dt"] =  执行这个sqls查询,返回新的datatable
    GridView1.DataSource = (DataTable)ViewState["dt"];
    GridView1.DataBind();
}

##第六步:实现GetAndConditionString方法##

实现GetAndConditionString方法,功能是拼接筛选项组装而成的sql语句过滤条件,第一个参数是列名,第二个参数是其列对应的viewstate的值,这也是核心部分。

private string GetAndConditionString(string ColumnName, string ViewStateString)
{
    /* 说明:
     * 每个if块 
     * 第一步:判断ViewState,如果是String.Empty,返回一个不可能查询出结果的条件,比如我给了五个俄文字母(这是一个临时方案,以后要让确认按钮变灰),开始第二步
     * 第二步:判断ViewState,如果是"-all-",如果是返回"",如果不是返回SelectedValuesJoined
     */
    string[] OrCondition;           //查询条件缓存 or条件
    string iRel = String.Empty;     //查询条件缓存 and条件
    string talbeName = "材料编码表";
    
    if (ViewStateString == SelectAllListItemText)  //全选 
    {
        iRel = String.Empty;    //材料编码的and条件是一个String.Empty
    }
    else   //不是全选
    {
        if (ViewStateString != String.Empty)   //SelectedValuesJoined不等于Null
        {
            OrCondition = ViewStateString.Split(';');  //分拆

            //组装前N-1和or条件
            for (int i = 0; i < OrCondition.Length - 1; i++)
            {
                iRel += "MaterialControl." + talbeName + ".[" + ColumnName + "]='" + OrCondition[i] + "' OR ";   //记得String结尾要有空格
            }
            //组装最后一个or条件
            iRel += "MaterialControl." + talbeName + ".[" + ColumnName + "]='" + OrCondition[OrCondition.Length - 1] + "' ";   //记得String结尾要有空格
        }
        else  //全选Item(点击取消筛选 或者 全选后点击确定)
        {
            iRel = String.Empty; 
        }
    }

    return iRel;
}

##第七步:最后增加一个处理空行的功能##

如果选项条件查询出来的结果是空集,要让gridview显示一个空行,不然整个gridview会因为没有数据行而消失,筛选操作就无法继续。

//空行的处理
protected void GridView1_DataBound(object sender, EventArgs e)
{
    if (GridView1.Rows.Count == 0)
    {
        DataTable plus = new DataTable();
        plus.Columns.Add("材料编码");
        plus.Columns.Add("材料名称");
       。。。。。。若干列
               
        plus.Rows.Add(plus.NewRow());
        GridView1.DataSource = plus;
        GridView1.DataBind();
    }
}

#七、代码下载#

http://download.csdn.net/detail/xiangcns/9291563
以后有时间做一个完整的demo,目前就把复选控件先放上来吧,照着说明步骤即可实现效果。

#八、最后来个动态效果图#

实际操作效果

这里写图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xiangcns/article/details/49980717

智能推荐

2024最新计算机毕业设计选题大全-程序员宅基地

文章浏览阅读1.6k次,点赞12次,收藏7次。大家好!大四的同学们毕业设计即将开始了,你们做好准备了吗?学长给大家精心整理了最新的计算机毕业设计选题,希望能为你们提供帮助。如果在选题过程中有任何疑问,都可以随时问我,我会尽力帮助大家。在选择毕业设计选题时,有几个要点需要考虑。首先,选题应与计算机专业密切相关,并且符合当前行业的发展趋势。选择与专业紧密结合的选题,可以使你们更好地运用所学知识,并为未来的职业发展奠定基础。要考虑选题的实际可行性和创新性。选题应具备一定的实践意义和应用前景,能够解决实际问题或改善现有技术。

dcn网络与公网_电信运营商DCN网络的演变与规划方法(The evolution and plan method of DCN)...-程序员宅基地

文章浏览阅读3.4k次。摘要:随着电信业务的发展和电信企业经营方式的转变,DCN网络的定位发生了重大的演变。本文基于这种变化,重点讨论DCN网络的规划方法和运维管理方法。Digest: With the development oftelecommunication bussiness and the change of management of telecomcarrier , DCN’s role will cha..._电信dcn

动手深度学习矩阵求导_向量变元是什么-程序员宅基地

文章浏览阅读442次。深度学习一部分矩阵求导知识的搬运总结_向量变元是什么

月薪已炒到15w?真心建议大家冲一冲数据新兴领域,人才缺口极大!-程序员宅基地

文章浏览阅读8次。近期,裁员的公司越来越多今天想和大家聊聊职场人的新出路。作为席卷全球的新概念ESG已然成为当前各个行业关注的最热风口目前,国内官方发布了一项ESG新证书含金量五颗星、中文ESG证书、完整ESG考试体系、名师主讲...而ESG又是与人力资源直接相关甚至在行业圈内成为大佬们的热门话题...当前行业下行,裁员的公司也越来越多大家还是冲一冲这个新兴领域01 ESG为什么重要?在双碳的大背景下,ESG已然成...

对比传统运营模式,为什么越拉越多的企业选择上云?_系统上云的前后对比-程序员宅基地

文章浏览阅读356次。云计算快速渗透到众多的行业,使中小企业受益于技术变革。最近微软SMB的一项研究发现,到今年年底,78%的中小企业将以某种方式使用云。企业希望投入少、收益高,来取得更大的发展机会。云计算将中小企业信息化的成本大幅降低,它们不必再建本地互联网基础设施,节省时间和资金,降低了企业经营风险。科技创新已成时代的潮流,中小企业上云是创新前提。云平台稳定、安全、便捷的IT环境,提升企业经营效率的同时,也为企业..._系统上云的前后对比

esxi网卡直通后虚拟机无网_esxi虚拟机无法联网-程序员宅基地

文章浏览阅读899次。出现选网卡的时候无法选中,这里应该是一个bug。3.保存退出,重启虚拟机即可。1.先随便选择一个网卡。2.勾先取消再重新勾选。_esxi虚拟机无法联网

随便推点

在LaTeX中使用.bib文件统一管理参考文献_egbib-程序员宅基地

文章浏览阅读913次。在LaTeX中,可在.tex文件的同一级目录下创建egbib.bib文件,所有的参考文件信息可以统一写在egbib.bib文件中,然后在.tex文件的\end{document}前加入如下几行代码:{\small\bibliographystyle{IEEEtran}\bibliography{egbib}}即可在文章中用~\cite{}宏命令便捷的插入文内引用,且文章的Reference部分会自动排序、编号。..._egbib

Unity Shader - Predefined Shader preprocessor macros 着色器预处理宏-程序员宅基地

文章浏览阅读950次。目录:Unity Shader - 知识点目录(先占位,后续持续更新)原文:Predefined Shader preprocessor macros版本:2019.1Predefined Shader preprocessor macros着色器预处理宏Unity 编译 shader programs 期间的一些预处理宏。(本篇的宏介绍随便看看就好,要想深入了解,还是直接看Unity...

大数据平台,从“治理”数据谈起-程序员宅基地

文章浏览阅读195次。本文目录:一、大数据时代还需要数据治理吗?二、如何面向用户开展大数据治理?三、面向用户的自服务大数据治理架构四、总结一、大数据时代还需要数据治理吗?数据平台发展过程中随处可见的数据问题大数据不是凭空而来,1981年第一个数据仓库诞生,到现在已经有了近40年的历史,相对数据仓库来说我还是个年轻人。而国内企业数据平台的建设大概从90年代末就开始了,从第一代架构出现到..._数据治理从0搭建

大学抢课python脚本_用彪悍的Python写了一个自动选课的脚本 | 学步园-程序员宅基地

文章浏览阅读2.2k次,点赞4次,收藏12次。高手请一笑而过。物理实验课别人已经做过3、4个了,自己一个还没做呢。不是咱不想做,而是咱不想起那么早,并且仅有的一次起得早,但是哈工大的服务器竟然超负荷,不停刷新还是不行,不禁感慨这才是真正的“万马争过独木桥“啊!服务器不给力啊……好了,废话少说。其实,我的想法很简单。写一个三重循环,不停地提交,直到所有的数据都accepted。其中最关键的是提交最后一个页面,因为提交用户名和密码后不需要再访问其..._哈尔滨工业大学抢课脚本

english_html_study english html-程序员宅基地

文章浏览阅读4.9k次。一些别人收集的英文站点 http://www.lifeinchina.cn (nice) http://www.huaren.us/ (nice) http://www.hindu.com (okay) http://www.italki.com www.talkdatalk.com (transfer)http://www.en8848.com.cn/yingyu/index._study english html

Cortex-M3双堆栈MSP和PSP_stm32 msp psp-程序员宅基地

文章浏览阅读5.5k次,点赞19次,收藏78次。什么是栈?在谈M3堆栈之前我们先回忆一下数据结构中的栈。栈是一种先进后出的数据结构(类似于枪支的弹夹,先放入的子弹最后打出,后放入的子弹先打出)。M3内核的堆栈也不例外,也是先进后出的。栈的作用?局部变量内存的开销,函数的调用都离不开栈。了解了栈的概念和基本作用后我们来看M3的双堆栈栈cortex-M3内核使用了双堆栈,即MSP和PSP,这极大的方便了OS的设计。MSP的含义是Main..._stm32 msp psp

推荐文章

热门文章

相关标签