当前位置: 首页 > news >正文

Qt QListView自定义树状导航控件

        大部分的软件都有多个页面,这时候就需要一个导航栏控件,通过在导航栏中选择某一栏,同时显示对应的页面。

        本文代码效果如下:

        本文的导航栏控件基于大佬 feiyangqingyun 的导航栏控件博客Qt/C++编写自定义控件46-树状导航栏_qt之实现自定义树状图控件-CSDN博客做了美化,修复了一些会导致崩溃的bug。

        本文代码:https://download.csdn.net/download/Sakuya__/89420773?spm=1001.2014.3001.5501icon-default.png?t=N7T8https://download.csdn.net/download/Sakuya__/89420773?spm=1001.2014.3001.5501        也可以在这里下载大佬的代码学习:NavListView: Qt 自定义的树形导航控件icon-default.png?t=N7T8https://gitee.com/qt-open-source-collection/NavListView


代码之路

NavListView.h

#ifndef NAVLISTVIEW_H
#define NAVLISTVIEW_H#include <QStyledItemDelegate>
#include <QAbstractListModel>
#include <QListView>
#include <vector>class NavListView;class NavDelegate : public QStyledItemDelegate
{Q_OBJECT
public:NavDelegate(QObject *parent);~NavDelegate();protected:QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const ;void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;private:NavListView *nav;
};class NavModel : public QAbstractListModel
{Q_OBJECT
public:NavModel(QObject *parent);~NavModel();public:struct TreeNode {QString iconName;QString label;int level;bool collapse;bool theFirst;bool theLast;QString info;std::list<TreeNode *> children;};struct ListNode {QString label;TreeNode *treeNode;};protected:int rowCount(const QModelIndex &parent) const;QVariant data(const QModelIndex &index, int role) const;private:std::vector<TreeNode *> treeNode;std::vector<ListNode> listNode;public slots:void readData(QString path);void setData(QStringList listItem);void collapse(const QModelIndex &index);private:void refreshList();
};class NavListView : public QListView
{Q_OBJECT
public:enum IcoStyle {IcoStyle_Cross = 0, IcoStyle_Triangle = 1};NavListView(QWidget *parent);~NavListView();bool getInfoVisible() const {return infoVisible;}bool getLineVisible() const {return lineVisible;}bool getIcoColorBg() const {return icoColorBg;}IcoStyle getIcoStyle() const {return style;}QColor getColorLine() const {return colorLine;}/// ====== 获取背景颜色函数QColor getColorBgNormal() const{return colorBgNormal;}QColor getColorBgSelected() const{return colorBgSelected;}QColor getColorBgHover() const{return colorBgHover;}QColor getColorBgNormalLeval2() const{return colorBgNormalLeval2;}QColor getColorBgSelectedLeval2() const{return colorBgSelectedLeval2;}QColor getColorBgHoverLeval2() const{return colorBgHoverLeval2;}/// ====== 获取文字颜色函数QColor getColorTextNormal() const {return colorTextNormal;}QColor getColorTextSelected() const {return colorTextSelected;}QColor getColorTextHover() const {return colorTextHover;}QColor getColorTextNormalLeval2() const {return colorTextNormalLeval2;}QColor getColorTextSelectedLeval2() const {return colorTextSelectedLeval2;}QColor getColorTextHoverLeval2() const {return colorTextHoverLeval2;}public slots:// 读取xml文件数据void readData(QString xmlPath);// 设置数据集合void setData(QStringList listItem);// 设置当前选中行void setCurrentRow(int row);// 设置是否显示提示信息void setInfoVisible(bool infoVisible);// 设置是否显示间隔线条void setLineVisible(bool lineVisible);// 设置伸缩图片是否采用背景色void setIcoColorBg(bool icoColorBg);// 设置伸缩图片样式void setIcoStyle(IcoStyle style);/// ====== 设置各种前景色背景色选中色void setColorLine(QColor colorLine);void setColorBg(QColor colorBgNormal,     QColor colorBgSelected,   QColor colorBgHover);void setColorText(QColor colorTextNormal, QColor colorTextSelected, QColor colorTextHover);void setColorBgLeval2(QColor colorBgNormal,     QColor colorBgSelected,   QColor colorBgHover);void setColorTextLeval2(QColor colorTextNormal, QColor colorTextSelected, QColor colorTextHover);private:NavModel *model;NavDelegate *delegate;bool infoVisible;               // 是否显示提示信息bool lineVisible;               // 是否显示分割线条bool icoColorBg;                // 伸缩图片是否使用颜色IcoStyle style;                 // 图标样式QColor colorLine;               // 线条颜色/// ====== leval为1时的效果QColor colorBgNormal;           // 正常背景色QColor colorBgSelected;         // 选中背景色QColor colorBgHover;            // 悬停背景色QColor colorTextNormal;         // 正常文字颜色QColor colorTextSelected;       // 选中文字颜色QColor colorTextHover;          // 悬停文字颜色/// ====== leval为2时的效果QColor colorBgNormalLeval2;     // 正常背景颜色QColor colorBgSelectedLeval2;   //QColor colorBgHoverLeval2;      //QColor colorTextNormalLeval2;   // 正常文字颜色QColor colorTextSelectedLeval2; //QColor colorTextHoverLeval2;    //
};#endif // NAVLISTVIEW_H

NavListView.cpp

#include "NavListView.h"#include <QPainter>
#include <QFile>
#include <qdom.h>
#include <QDebug>NavDelegate::NavDelegate(QObject *parent) : QStyledItemDelegate(parent)
{nav = (NavListView *)parent;
}NavDelegate::~NavDelegate()
{}QSize NavDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{NavModel::TreeNode *node = (NavModel::TreeNode *)index.data(Qt::UserRole).toULongLong();if (node->level == 1){return QSize(192, 71);}else{return QSize(182, 48);}
}void NavDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{painter->setRenderHint(QPainter::Antialiasing);NavModel::TreeNode *node = (NavModel::TreeNode *)index.data(Qt::UserRole).toULongLong();QColor colorBg;QColor colorText;QFont  fontText;int    iconSize = 0, leftMargin = 0, topMargin = 0;if(1 == node->level){if (option.state & QStyle::State_Selected){colorBg   = nav->getColorBgSelected();colorText = nav->getColorTextSelected();}else if (option.state & QStyle::State_MouseOver){colorBg   = nav->getColorBgHover();colorText = nav->getColorTextHover();}else{colorBg   = nav->getColorBgNormal();colorText = nav->getColorTextNormal();}iconSize    = 32;leftMargin  = 32;topMargin   = 20;fontText.setPixelSize(20);painter->setBrush(QBrush(nav->getColorBgNormal()));painter->setPen(Qt::transparent);painter->drawRoundedRect(option.rect, 8, 20, Qt::RelativeSize);}else if(2 == node->level){if (option.state & QStyle::State_Selected){colorBg   = nav->getColorBgSelectedLeval2();colorText = nav->getColorTextSelectedLeval2();}else if (option.state & QStyle::State_MouseOver){colorBg = nav->getColorBgHoverLeval2();colorText = nav->getColorTextHoverLeval2();}else{colorBg   = nav->getColorBgNormalLeval2();colorText = nav->getColorTextNormalLeval2();}iconSize   = 24;leftMargin = 25;topMargin  = 13;fontText.setPixelSize(18);QRect rectLevel2 = option.rect;rectLevel2.setX(option.rect.x() + 12);if (node->theFirst){rectLevel2.setHeight(option.rect.height() + 4);rectLevel2.setWidth(option.rect.width() + 8);painter->setBrush(QBrush(nav->getColorBgNormalLeval2()));painter->setPen(Qt::transparent);painter->drawRoundedRect(rectLevel2, 8, 20, Qt::RelativeSize);}else if (node->theLast){rectLevel2.setY(option.rect.y() - 4);rectLevel2.setWidth(option.rect.width() + 8);painter->setBrush(QBrush(nav->getColorBgNormalLeval2()));painter->setPen(Qt::transparent);painter->drawRoundedRect(rectLevel2, 8, 20, Qt::RelativeSize);}else{painter->fillRect(rectLevel2, nav->getColorBgNormalLeval2());}}/// ====== 菜单选项背景颜色if (1 == node->level && option.state & QStyle::State_Selected){QRect rectMenu = option.rect;rectMenu.setWidth(option.rect.width()  - 20);rectMenu.setHeight(option.rect.height()- 10);rectMenu.setX(option.rect.x() + 10);rectMenu.setY(option.rect.y() + 10);painter->setBrush(QBrush(colorBg));painter->setPen(Qt::transparent);painter->drawRoundedRect(rectMenu, 8, 20, Qt::RelativeSize);}/// ====== 绘制图标QPixmap pixMap;pixMap.load(node->iconName);QRect rectIcon = option.rect;rectIcon.setX(option.rect.x()+leftMargin);rectIcon.setY(option.rect.y()+topMargin);rectIcon.setWidth(iconSize);rectIcon.setHeight(iconSize);painter->drawPixmap(rectIcon, pixMap);/// ====== 绘制条目文字if(option.state & QStyle::State_Selected){painter->setOpacity(1);}else{painter->setOpacity(0.5);}painter->setPen(QPen(colorText));int margin = 72;if (node->level == 2){margin = 84;}QRect rect = option.rect;rect.setX(rect.x() + margin);painter->setFont(fontText);painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, index.data(Qt::DisplayRole).toString());painter->setOpacity(1);/// ====== 绘制分割线QRect rectLine = option.rect;rectLine.setX(option.rect.x()+16);rectLine.setY(option.rect.y()-1);rectLine.setWidth(168);rectLine.setHeight(1);QPixmap pixMapLine;pixMapLine.load(":/Images/Line.png");painter->drawPixmap(rectLine, pixMapLine);
}NavModel::NavModel(QObject *parent)	: QAbstractListModel(parent)
{}NavModel::~NavModel()
{for (std::vector<TreeNode *>::iterator it = treeNode.begin(); it != treeNode.end();) {for (std::list<TreeNode *>::iterator child = (*it)->children.begin(); child != (*it)->children.end();) {delete(*child);child = (*it)->children.erase(child);}delete(*it);it = treeNode.erase(it);}
}void NavModel::readData(QString path)
{QFile xml(path);if (!xml.open(QIODevice::ReadOnly | QIODevice::Text)) {return;}QDomDocument doc;if (!doc.setContent(&xml, false)){return;}treeNode.clear();listNode.clear();QDomNode root = doc.documentElement().firstChildElement("layout");QDomNodeList children = root.childNodes();for (int i = 0; i != children.count(); ++i){QDomElement nodeInfo = children.at(i).toElement();TreeNode *node = new TreeNode;node->label    = nodeInfo.attribute("label");node->collapse = nodeInfo.attribute("collapse").toInt();node->info     = nodeInfo.attribute("info");node->level    = 1;QDomNodeList secondLevel = nodeInfo.childNodes();for (int j = 0; j != secondLevel.count(); ++j){QDomElement secNodeInfo = secondLevel.at(j).toElement();TreeNode *secNode = new TreeNode;secNode->label = secNodeInfo.attribute("label");secNode->info  = secNodeInfo.attribute("info");secNode->collapse = false;secNode->level    = 2;secNode->theLast  = (j == secondLevel.count() - 1 && i != children.count() - 1);node->children.push_back(secNode);}treeNode.push_back(node);}refreshList();beginResetModel();endResetModel();
}void NavModel::setData(QStringList listItem)
{int count = listItem.count();if (count == 0) {return;}treeNode.clear();listNode.clear();// listItem格式: 标题|父节点标题(父节点为空)|是否展开|提示信息for (int i = 0; i < count; i++){QString item = listItem.at(i);QStringList list = item.split("|");if (list.count() < 4){continue;}// 首先先将父节点即父节点标题为空的元素加载完毕QString title       = list.at(0);QString fatherTitle = list.at(1);QString collapse    = list.at(2);QString info        = list.at(3);QString iconFile    = list.at(4);if (fatherTitle.isEmpty()){TreeNode *node = new TreeNode;node->label     = title;node->collapse  = collapse.toInt();node->info      = info;node->level     = 1;node->iconName  = iconFile;// 先计算该父节点有多少个子节点int secCount = 0;for (int j = 0; j < count; j++){QString secItem = listItem.at(j);QStringList secList = secItem.split("|");if (secList.count() < 4){continue;}QString secFatherTitle  = secList.at(1);if (secFatherTitle == title){secCount++;}}// 查找该父节点是否有对应子节点,有则加载int currentCount = 0;for (int j = 0; j < count; j++){QString secItem = listItem.at(j);QStringList secList = secItem.split("|");if (secList.count() < 4){continue;}QString secTitle        = secList.at(0);QString secFatherTitle  = secList.at(1);QString secInfo         = secList.at(3);QString secIconName     = secList.at(4);if (secFatherTitle == title){currentCount++;TreeNode *secNode = new TreeNode;secNode->label    = secTitle;secNode->info     = secInfo;secNode->collapse = false;secNode->level    = 2;secNode->theFirst = (currentCount == 1);secNode->theLast  = (currentCount == secCount);secNode->iconName = secIconName;node->children.push_back(secNode);}}treeNode.push_back(node);}}refreshList();beginResetModel();endResetModel();
}int NavModel::rowCount(const QModelIndex &parent) const
{return listNode.size();
}QVariant NavModel::data(const QModelIndex &index, int role) const
{if (!index.isValid()) {return QVariant();}if (index.row() >= listNode.size() || index.row() < 0) {return QVariant();}if (role == Qt::DisplayRole) {return listNode[index.row()].label;} else if (role == Qt::UserRole) {return reinterpret_cast<quint64>(listNode[index.row()].treeNode);}return QVariant();
}void NavModel::refreshList()
{listNode.clear();for (std::vector<TreeNode *>::iterator it = treeNode.begin(); it != treeNode.end(); ++it) {ListNode node;node.label = (*it)->label;node.treeNode = *it;listNode.push_back(node);if ((*it)->collapse) {continue;}for (std::list<TreeNode *>::iterator child = (*it)->children.begin(); child != (*it)->children.end(); ++child) {ListNode node;node.label = (*child)->label;node.treeNode = *child;node.treeNode->theLast = false;listNode.push_back(node);}if (!listNode.empty()) {listNode.back().treeNode->theLast = true;}}
}void NavModel::collapse(const QModelIndex &index)
{TreeNode *node = listNode[index.row()].treeNode;if (node->children.size() == 0) {return;}node->collapse = !node->collapse;if (!node->collapse) {beginInsertRows(QModelIndex(), index.row() + 1, index.row() + node->children.size());endInsertRows();} else {beginRemoveRows(QModelIndex(), index.row() + 1, index.row() + node->children.size());endRemoveRows();}// 刷新放在删除行之后,放在删除行之前可能导致rowCount返回数据错误refreshList();
}NavListView::NavListView(QWidget *parent) : QListView(parent)
{infoVisible = true;lineVisible = true;icoColorBg = false;style = NavListView::IcoStyle_Cross;colorLine         = QColor(214, 216, 224);colorBgNormal     = QColor(239, 241, 250);colorBgSelected   = QColor(133, 153, 216);colorBgHover      = QColor(209, 216, 240);colorTextNormal   = QColor(58, 58, 58);colorTextSelected = QColor(255, 255, 255);colorTextHover    = QColor(59, 59, 59);this->setMouseTracking(true);model = new NavModel(this);delegate = new NavDelegate(this);connect(this, SIGNAL(clicked(QModelIndex)), model, SLOT(collapse(QModelIndex)));
}NavListView::~NavListView()
{delete model;delete delegate;
}void NavListView::readData(QString xmlPath)
{model->readData(xmlPath);this->setModel(model);this->setItemDelegate(delegate);
}void NavListView::setData(QStringList listItem)
{model->setData(listItem);this->setModel(model);this->setItemDelegate(delegate);
}void NavListView::setCurrentRow(int row)
{QModelIndex index = model->index(row, 0);setCurrentIndex(index);
}void NavListView::setInfoVisible(bool infoVisible)
{this->infoVisible = infoVisible;
}void NavListView::setLineVisible(bool lineVisible)
{this->lineVisible = lineVisible;
}void NavListView::setIcoColorBg(bool icoColorBg)
{this->icoColorBg = icoColorBg;
}void NavListView::setIcoStyle(NavListView::IcoStyle style)
{this->style = style;
}void NavListView::setColorLine(QColor colorLine)
{this->colorLine = colorLine;
}void NavListView::setColorBg(QColor colorBgNormal,  ///< 正常背景颜色QColor colorBgSelected,///< 选中背景颜色QColor colorBgHover)   ///< 鼠标悬停背景颜色
{this->colorBgNormal   = colorBgNormal;this->colorBgSelected = colorBgSelected;this->colorBgHover    = colorBgHover;
}
void NavListView::setColorText(QColor colorTextNormal,  ///< 正常字体颜色QColor colorTextSelected,///< 选中字体颜色QColor colorTextHover)   ///< 鼠标悬停字体颜色
{this->colorTextNormal   = colorTextNormal;this->colorTextSelected = colorTextSelected;this->colorTextHover    = colorTextHover;
}
void NavListView::setColorBgLeval2(QColor _colorBgNormalLeval2,QColor _colorBgSelectedLeval2,QColor _colorBgHoverLeval2)
{this->colorBgNormalLeval2   = _colorBgNormalLeval2;this->colorBgSelectedLeval2 = _colorBgSelectedLeval2;this->colorBgHoverLeval2    = _colorBgHoverLeval2;
}
void NavListView::setColorTextLeval2(QColor _colorTextNormalLeval2,QColor _colorTextSelectedLeval2,QColor _colorTextHoverLeval2)
{this->colorTextNormalLeval2   = _colorTextNormalLeval2;this->colorTextSelectedLeval2 = _colorTextSelectedLeval2;this->colorTextHoverLeval2    = _colorTextHoverLeval2;
}

NavigationList.h

#ifndef NAVIGATIONLIST_H
#define NAVIGATIONLIST_H#include <QWidget>
#include <QPainter>
#include <QStyleOption>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class NavigationList; }
QT_END_NAMESPACEclass NavigationList : public QWidget
{Q_OBJECT
public:explicit NavigationList(QWidget *parent = nullptr);~NavigationList();void initTreeView();protected:void paintEvent(QPaintEvent* _event) override;public slots:void slotListViewPressed(const QModelIndex &);signals:void signalPageSwitch(QString page);      // 页面切换信号private:Ui::NavigationList *ui;bool m_isHideAdditional = true;
};
#endif // NAVIGATIONLIST_H

NavigationList.cpp

#include "NavigationList.h"
#include "ui_NavigationList.h"NavigationList::NavigationList(QWidget *parent) :QWidget(parent),ui(new Ui::NavigationList)
{ui->setupUi(this);initTreeView();connect(ui->listViewNavigation, &NavListView::pressed, this, &NavigationList::slotListViewPressed);ui->listViewNavigation->setCurrentRow(0);
}NavigationList::~NavigationList()
{delete ui;
}void NavigationList::paintEvent(QPaintEvent* _event)
{Q_UNUSED(_event)QStyleOption n_styleOption;n_styleOption.init(this);QPainter painter(this);style()->drawPrimitive(QStyle::PE_Widget, &n_styleOption, &painter, this);
}void NavigationList::initTreeView()
{ui->listViewNavigation->setIcoColorBg(false);ui->listViewNavigation->setColorLine(QColor("#FFFFFF"));ui->listViewNavigation->setColorBg(QColor("#016BFF"),QColor("#2A83FF"),QColor("#2A83FF"));ui->listViewNavigation->setColorText(QColor("#FFFFFF"),QColor("#FFFFFF"),QColor(0, 0, 0));ui->listViewNavigation->setColorBgLeval2(QColor("#EBF1FF"),QColor("#EBF1FF"),QColor("#EBF1FF"));ui->listViewNavigation->setColorTextLeval2(QColor("#000000"),QColor("#000000"),QColor("#6D6D6D"));// 设置数据方式QStringList listItem;listItem.append(QString::fromLocal8Bit("Tab1||0||:/Images/1.png|"));listItem.append(QString::fromLocal8Bit("Tab2||0||:/Images/2.png|"));listItem.append(QString::fromLocal8Bit("Tab3||1||:/Images/3.png|"));listItem.append(QString::fromLocal8Bit("Tab4|Tab3|||:/Images/4.png|"));listItem.append(QString::fromLocal8Bit("Tab5|Tab3|||:/Images/5.png|"));listItem.append(QString::fromLocal8Bit("Tab6|Tab3|||:/Images/6.png|"));listItem.append(QString::fromLocal8Bit("Tab7|Tab3|||:/Images/7.png|"));listItem.append(QString::fromLocal8Bit("Tab8||0||:/Images/8.png|"));listItem.append(QString::fromLocal8Bit("Tab9||0||:/Images/9.png|"));ui->listViewNavigation->setData(listItem);
}void NavigationList::slotListViewPressed(const QModelIndex &)
{// 获取到点击的某一行,再根据点击显示对应的界面QModelIndex index = ui->listViewNavigation->currentIndex();QString text = index.data().toString();emit signalPageSwitch(text);
}

NavigationList.ui

        只有一个QListView控件,被提升成了上面的NavListView类

        其中listViewNavigation控件添加了如下的样式表:

NavDelegate
{background-color:"#016BFF";
}
QListView#listViewNavigation
{border-top-left-radius: 8px;border-bottom-left-radius: 8px;background-color:"#016BFF";
}

 

相关文章:

  • 【学习】程序员资源网址
  • ASP.NET MVC-简单例子
  • 使用QT绘制简单的动态数据折线图
  • Laravel 中 使用模型作为标志
  • 多路h265监控录放开发-(1)建立head窗口并实现鼠标拖动整个窗口
  • 聊聊系统架构之负载均衡优化实践
  • 【调试笔记-20240618-Windows-pnpm 更新出现 Cannot find module 问题的解决方法】
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • 如何学习C语言
  • Excel 常用技巧(四)
  • Eureka 学习笔记(1)
  • 亿达中国武汉园区入选“武汉市科技金融工作站”及“武汉市线下首贷服务站”
  • 【JavaScript脚本宇宙】玩转图像处理:从基础到高级,这些库你不能错过!
  • 今年的618,似乎很平淡!
  • 计算机网络:运输层 - 概述
  • Akka系列(七):Actor持久化之Akka persistence
  • Angular4 模板式表单用法以及验证
  • crontab执行失败的多种原因
  • Golang-长连接-状态推送
  • Java 多线程编程之:notify 和 wait 用法
  • SpiderData 2019年2月25日 DApp数据排行榜
  • tensorflow学习笔记3——MNIST应用篇
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 回顾 Swift 多平台移植进度 #2
  • 机器学习 vs. 深度学习
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • -- 数据结构 顺序表 --Java
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 追踪解析 FutureTask 源码
  • ​第20课 在Android Native开发中加入新的C++类
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #70结构体案例1(导师,学生,成绩)
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • (1)Nginx简介和安装教程
  • (3)STL算法之搜索
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (第30天)二叉树阶段总结
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (三)c52学习之旅-点亮LED灯
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (四)事件系统
  • (已解决)什么是vue导航守卫
  • (转)setTimeout 和 setInterval 的区别
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET C# 操作Neo4j图数据库
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .net core 依赖注入的基本用发
  • .NET 常见的偏门问题
  • .考试倒计时43天!来提分啦!