微信原生組件|基於小程式實現音視頻通話

来源:https://www.cnblogs.com/zegodeveloper/archive/2022/09/21/16715772.html
-Advertisement-
Play Games

1 微信小程式原生推拉流組件功能簡介 本文將介紹如何使用微信小程式原生推拉流組件 <live-pusher> 和 <live-player> 進行推拉流,快速實現一個簡單的實時音視頻通話。 由於微信小程式原生推拉流組件使用起來比較複雜,推薦開發者使用即構封裝的音視頻SDK <zego-push> 和 ...


1 微信小程式原生推拉流組件功能簡介

本文將介紹如何使用微信小程式原生推拉流組件 <live-pusher> 和 <live-player> 進行推拉流,快速實現一個簡單的實時音視頻通話。

由於微信小程式原生推拉流組件使用起來比較複雜,推薦開發者使用即構封裝的音視頻SDK <zego-push> 和 <zego-player> 組件實現視頻通話,可參考 實現視頻通話

2 實現微信小程式音視頻通話的前提條件

在實現基本的實時音視頻功能之前,請確保:

3 即構音視頻SDK實現流程

用戶通過 ZEGO Express SDK 即構音視頻SDK進行視頻通話的基本流程為:

用戶 A、B 加入房間,用戶 B 預覽並將音視頻流推送到 ZEGO 雲服務(推流),用戶 A 收到用戶 B 推送音視頻流的通知之後,在通知中播放用戶 B 的音視頻流(拉流)。

下載.png

3.1 配置微信小程式後臺

在初始化 音視頻SDK 前,需要在 微信公眾平臺 中進行如下配置:

  • 伺服器功能變數名稱配置:在“小程式後臺 > 開發管理 > 開發設置 > 伺服器功能變數名稱”中,按照協議分類,將即構 Server 地址、LogUrl、以及用戶業務需要用到的地址填到指定的“request合法功能變數名稱”或“socket合法功能變數名稱”中。
    下載1.png

  • 相關功能開啟:在“小程式後臺 > 開發管理 > 介面設置 > 介面許可權”中,打開 實時播放音視頻流實時錄製音視頻流 功能開關。
    下載2.png

3.2 即構音視頻SDK初始化

1. 創建音視頻通話界面

根據音視頻場景需要,為您的項目創建音視頻通話的用戶界面。我們推薦您在項目中添加如下元素:

  • 本地預覽視窗
  • 遠端視頻視窗
  • 結束按鈕
    下載3.png

小程式推流組件 <live-pusher> 中的 "video-width" 和 "video-height" 存在相容性問題,可能會出現設置不生效的情況。

參考界面代碼:

<view wx:if="{{canShow== 1}}" class="">
  <view class="containerBase">
    <live-pusher class="testpusher" 
    wx:if="{{pusher.url}}" 
    url="{{pusher.url}}"  
    mode="{{pusher.mode}}"
    autopush="{{pusher.autopush}}"
    enable-camera="{{pusher.enableCamera}}"
    enable-mic="{{pusher.enableMic}}"
    muted="{{!pusher.enableMic}}"
    enable-agc="{{pusher.enableAgc}}"
    enable-ans="{{pusher.enableAns}}"
    zoom="{{pusher.enableZoom}}"
    min-bitrate="{{pusher.minBitrate}}"
    max-bitrate="{{pusher.maxBitrate}}"
    video-width="{{pusher.videoWidth}}"
    video-height="{{pusher.videoHeight}}"
    beauty="{{pusher.beautyLevel}}"
    whiteness="{{pusher.whitenessLevel}}"
    orientation="{{pusher.videoOrientation}}"
    device-position="{{pusher.frontCamera}}"
    remote-mirror="{{pusher.enableRemoteMirror}}"
    local-mirror="{{pusher.localMirror}}"
    background-mute="{{pusher.enableBackgroundMute}}"
    audio-quality="{{pusher.audioQuality}}"
    audio-volume-type="{{pusher.audioVolumeType}}"
    audio-reverb-type="{{pusher.audioReverbType}}"
    waiting-image="{{pusher.waitingImage}}"
    beauty-style="{{pusher.beautyStyle}}"
    filter="{{pusher.filter}}"
    bindstatechange="onPushStateChange" 
    bindaudiovolumenotify="bindaudiovolumenotify"  
    bindnetstatus="onPushNetStateChange"
    waiting-image="https://storage.zego.im/downloads/pause_publish.png"></live-pusher>
      <live-player  wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}" 
      src= "{{item.url}}"
      mode= "RTC"
      autoplay= "{{item.autoplay}}"
      mute-audio= "{{item.muteAudio}}"
      mute-video= "{{item.muteVideo}}"
      orientation= "{{item.orientation}}"
      object-fit= "{{item.objectFit}}"
      min-cache= "{{item.minCache}}"
      max-cache= "{{item.maxCache}}"
      sound-mode= "{{item.soundMode}}"
      enable-recv-message= "{{item.enableRecvMessage}}"
      auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
      auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange"  bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange"></live-player>
  </view>
  <view class="index-container">
    <view class='input-container'>
      <input value="{{roomID}}" bindinput="bindKeyInput" placeholder="請輸入房間 ID" placeholder-style='color: #b3b3b3; font-size: 14px;' class="room-input" />
      <text class="tip"></text>
    </view>
    <view class="button-container">
      <button bindtap="openRoom" data-role="1" data-option="videoAndAudio" hover-class="none" class="openRoom">
        加入房間(推流)
      </button>
     
      
      <button bindtap="logout" hover-class="none">退出房間</button>
    </view>
  </view>
</view>
<view class="settings">
  <button wx:if="{{canShow==0}}" open-type="openSetting" bindopensetting="settingCallback">
    授權使用攝像頭和麥克風
  </button>
</view>

2. 創建音視頻SDK引擎

創建 ZegoExpressEngine 引擎實例,將申請到的 AppID 傳入參數 “appID”,將獲取到的 Server 地址傳入參數 “server”。

// 初始化實例
zg = new ZegoExpressEngine(appID, server);

如果需要註冊回調,開發者可根據實際需要,實現 ZegoEvent 中的某些方法,創建引擎後可通過調用 on 介面設置回調。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 與房間斷開了連接
	// ...
    }

    if (state == 'CONNECTING') {
        // 與房間嘗試連接中
	// ...
    }

    if (state == 'CONNECTED') {
        // 與房間連接成功
	// ...
    }
})

3.3 登錄音視頻房間

1. 獲取房間登錄 Token

登錄房間需要用於驗證身份的 Token,獲取方式請參考 用戶許可權控制。如需快速調試,建議使用控制台生成的臨時 Token,生成臨時 Token 的具體操作請參考 控制台 - 項目管理

2. 登錄音視頻房間

您可以調用 SDK 的 loginRoom 介面,傳入房間 ID 參數 “roomID”、“token” 和用戶參數 “user”,登錄房間。您可通過監聽 roomStateUpdate 回調實時監控自己在本房間內的連接狀態,具體請參考 4.1 常見通知回調 中的“4.1.1 我在房間內的連接狀態變化通知”。

roomID 和 user 的參數由您本地生成,但是需要滿足以下條件:

  • 同一個 AppID 內,需保證 “roomID” 全局唯一。
  • 同一個 AppID 內,需保證 “userID” 全局唯一,建議開發者將 “userID” 與自己業務的賬號系統進行關聯。

為避免錯過任何通知,您需要在登錄房間前先設置所有的監聽回調(如房間狀態、用戶狀態、流狀態、推拉流狀態等),具體請參考 4.1 常見通知回調

// 登錄房間,成功則返回 true
const result = await zg.loginRoom(roomID, token, {userID, userName});

3.4 將自己的音視頻流推送到 ZEGO 即構音視頻雲

3.4.1 初始化小程式組件實例

調用 initContext 介面初始化小程式組件。

小程式組件中用於存儲推流屬性 pusher 和拉流屬性列表 playerList 兩個欄位需要傳給 SDK,SDK 後續將通過傳入的兩個欄位對相應的推拉流作狀態及視圖更新處理。

zg.initContext({
     wxContext: this,
     pushAtr: "pusher", // 對象名,對象屬性與 live-pusher 中的屬性為映射關係
     playAtr: "playerList" // 對象名,對象屬性與 live-player 中的屬性為映射關係
})

即構音視頻SDK 在內部會對推拉流實例進行操作以及視圖更新,開發者無需保存推拉流實例和調用小程式 setData 介面更新視圖,避免與 SDK 發生衝突。後續可通過 getPusherInstancegetPlayerInstance 介面獲取推拉流實例。

3.4.2 創建對應業務場景的 WXML

根據您的業務場景需求,編寫 WXML 文件,創建推拉流組件 <live-pusher> 和 <live-player>。

  • <live-pusher> 組件用於小程式的實時推送音視頻流功能。
  • <live-player> 組件用戶小程式的實時播放音視頻流功能。

WXML 的具體含義與用法請參考微信官網文檔中的介紹 WXML

WXML 中的 pusher 與 playerList,必須與初始化小程式組件 initContext 中定義的這兩個欄位屬性名保持一致,後續 SDK 調用推拉流介面之後才能正確地進行狀態及視圖更新。

bindstatechange 表示播放狀態變化事件;bindaudiovolumenotify 表示播放音量大小通知;bindnetstatus 表示網路狀態通知。

<live-pusher class="testpusher" 
    wx:if="{{pusher.url}}" 
    url="{{pusher.url}}"  
    mode="{{pusher.mode}}"
    autopush="{{pusher.autopush}}"
    enable-camera="{{pusher.enableCamera}}"
    enable-mic="{{pusher.enableMic}}"
    muted="{{!pusher.enableMic}}"
    enable-agc="{{pusher.enableAgc}}"
    enable-ans="{{pusher.enableAns}}"
    enable-ear-monitor="{{pusher.enableEarMonitor}}"
    auto-focus="{{pusher.enableAutoFocus}}"
    zoom="{{pusher.enableZoom}}"
    min-bitrate="{{pusher.minBitrate}}"
    max-bitrate="{{pusher.maxBitrate}}"
    video-width="{{pusher.videoWidth}}"
    video-height="{{pusher.videoHeight}}"
    beauty="{{pusher.beautyLevel}}"
    whiteness="{{pusher.whitenessLevel}}"
    orientation="{{pusher.videoOrientation}}"
    aspect="{{pusher.videoAspect}}"
    device-position="{{pusher.frontCamera}}"
    remote-mirror="{{pusher.enableRemoteMirror}}"
    local-mirror="{{pusher.localMirror}}"
    background-mute="{{pusher.enableBackgroundMute}}"
    audio-quality="{{pusher.audioQuality}}"
    audio-volume-type="{{pusher.audioVolumeType}}"
    audio-reverb-type="{{pusher.audioReverbType}}"
    waiting-image="{{pusher.waitingImage}}"
    beauty-style="{{pusher.beautyStyle}}"
    filter="{{pusher.filter}}"
    bindstatechange="onPushStateChange" 
    bindaudiovolumenotify="bindaudiovolumenotify"  
    bindnetstatus="onPushNetStateChange"
    waiting-image="https://storage.zego.im/downloads/pause_publish.png">
</live-pusher>
<live-player  wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}" 
      src= "{{item.url}}"
      mode= "RTC"
      autoplay= "{{item.autoplay}}"
      mute-audio= "{{item.muteAudio}}"
      mute-video= "{{item.muteVideo}}"
      orientation= "{{item.orientation}}"
      object-fit= "{{item.objectFit}}"
      min-cache= "{{item.minCache}}"
      max-cache= "{{item.maxCache}}"
      sound-mode= "{{item.soundMode}}"
      enable-recv-message= "{{item.enableRecvMessage}}"
      auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
      auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange"  bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange">
</live-player>

3.4.3 推送音視頻流到 ZEGO 即構音視頻雲

必須完成初始化小程式組件實例和創建業務場景的 WXML 之後,才能調用 SDK 介面創建推流和拉流實例。

用戶調用 SDK 的 createPusher 介面創建推流實例,並通過調用實例對象上的 start 介面,傳入流 ID 參數 “streamID”。您可通過監聽 publisherStateUpdate 回調知曉推流是否成功,具體請參考 4.1 常見通知回調 中的“4.1.4 用戶推送音視頻流的狀態通知”。

“streamID” 由您本地生成,但是需要保證:

  • 同一個 AppID 下,“streamID” 全局唯一。如果同一個 AppID 下,不同用戶各推了一條 “streamID” 相同的流,後推流的用戶推流失敗。
  • “streamID” 長度不超過 256 位元組的字元串。僅支持數字,英文字元和 “~”,“!”,“@”,“$”,“%”,“^”,“&”,“*”,“(”,“)”,“_”,“+”,“=”,“-”,“`”,“;”,“’”,“,”,“.”,“<”,“>”,“/”,“\”。
// 推流方登錄房間成功後觸發推流
 const pusher = zg.createPusher();
 pusher.start("streamID_xxx");

3.5 拉取其他用戶的音視頻

進行視頻通話時,我們需要拉取到其他用戶的音視頻。

用戶先調用 getPlayerInstance介面,根據傳入的流 ID 參數 “streamID”,獲取 streamID 對應的拉流實例,然後通過調用拉流實例對象的 play 介面開始拉流。您可通過監聽 playerStateUpdate 回調知曉是否成功拉取音視頻,具體請參考 4.1 常見通知回調 中的“4.1.5 用戶拉取音視頻流的狀態通知”。

遠端用戶推送的 “streamID” 可以從 roomStreamUpdate 回調中獲得,具體回調設置請參考 4.1 常見通知回調 中的“4.1.3 房間內流狀態變更的通知”。

// 在 SDK 的回調 roomStreamUpdate 中獲取拉流 streamID
// 當用戶加入或離開房間時,該事件被觸發
zg.on("roomStreamUpdate", (roomID, updateType, streamList) => {
    console.log("roomStreamUpdate", roomID, updateType, streamList);
    if (updateType === "ADD") {
        streamList.forEach(i => {
              zg.getPlayerInstance(i.streamID).play();
        })
    } else {
       streamList.forEach(i => {
              zg.getPlayerInstance(i.streamID).stop();
       })
    }
});

4 小程式音視頻通話的常用功能

4.1 常見音視頻房間通知回調

4.1.1 我在房間內的連接狀態變化通知

roomStateUpdate:本地調用 loginRoom 加入房間時,您可通過監聽該回調實時監控自己在本房間內的連接狀態。

用戶可以在回調中根據不同狀態處理業務邏輯。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 與房間斷開了連接
	// ...
    }

    if (state == 'CONNECTING') {
        // 與房間嘗試連接中
	// ...
    }

    if (state == 'CONNECTED') {
        // 與房間連接成功
	// ...
    }
})

4.png

4.1.2 其他用戶進出房間的通知

roomUserUpdate:同一房間內的其他用戶進出房間時,您可通過此回調收到通知。登錄房間後,當房間內有用戶新增或刪除時,SDK 會通過該回調通知。

只有調用 loginRoom 介面登錄房間時傳入 ZegoRoomConfig 配置,且 “userUpdate” 參數取值為 “true” 時,用戶才能收到 roomUserUpdate 回調。

// 用戶狀態更新回調
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    console.warn(
        `roomUserUpdate: room ${roomID}, user ${updateType === 'ADD' ? 'added' : 'left'} `,
        JSON.stringify(userList),
    );
});

4.1.3 房間內流狀態變更的通知

roomStreamUpdate:流狀態更新回調。登錄房間後,當房間內有用戶新推送或刪除音視頻流時,SDK 會通過該回調通知。

// 流狀態更新回調
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // 流新增,開始拉流
    } else if (updateType == 'DELETE') {
        // 流刪除,停止拉流
    }
});

4.1.4 用戶推送音視頻流的狀態通知

  • 推流狀態事件

微信小程式會在 <live-pusher> 的 bindstatechange 綁定的方法中通知出推流狀態事件,開發者需要:

a. 在 bindstatechange 綁定的回調函數中,調用 SDK 的 updatePlayerState 介面將推流狀態事件透傳給 SDK。

b. 在 SDK 的 publisherStateUpdate 回調中處理推流的開始、失敗狀態。

// live-pusher 綁定推流事件
onPushStateChange(e) {
    // 透傳推流事件給 SDK
    zg.updatePlayerState(this.data.publishStreamID, e);
},

// 推流後,伺服器主動推過來的,流狀態更新
// NO_PUBLISH:未推流狀態,PUBLISH_REQUESTING:正在請求推流狀態,PUBLISHING:正在推流狀態
// state: "PUBLISHING" | "NO_PUBLISH" | "PUBLISH_REQUESTING";
zg.on("publisherStateUpdate", (result) => {
    console.log("publishStateUpdate", result.state);
});
  • 推流網路事件

微信小程式會在 <live-pusher> 的 bindnetstatus 綁定的方法中通知出推流網路事件,開發者需要在對應的小程式回調中,調用 SDK 的 updatePlayerNetStatus 介面將推流網路事件透傳給 SDK。

// live-pusher 綁定網路狀態事件
onPushNetStateChange(e) {
    //透傳網路狀態事件給 SDK
    zg.updatePlayerNetStatus(this.data.publishStreamID, e);
},


// SDK 推流網路質量回調
zg.on("publishQualityUpdate", (streamID, publishStats) => {
    console.log("publishQualityUpdate", streamID, publishStats);
});

4.1.5 用戶拉取音視頻流的狀態通知

  • 拉流狀態事件

微信小程式會在 <live-player> 的 bindstatechange 綁定的方法中通知出拉流狀態事件,開發者需要:

a. 在 bindstatechange 綁定的回調函數中,調用 SDK 的 updatePlayerState 介面將拉流狀態事件透傳給 SDK。

b. 在 SDK 提供的 playerStateUpdate 回調中處理拉流的開始或失敗狀態。

// live-player 綁定的拉流事件
onPlayStateChange(e) {
    // 透傳拉流事件給 SDK
    zg.updatePlayerState(e.currentTarget.id, e);
},

// 伺服器主動推過來的流的播放狀態
// 視頻播放狀態通知;state: "NO_PLAY" | "PLAY_REQUESTING" | "PLAYING";
zg.on("playerStateUpdate", (result) => {
    console.log("playStateUpdate", result.state);
});
  • 拉流網路事件

微信小程式會在 <live-player> 的 bindnetstatus 綁定的方法中通知出拉流網路事件,開發者需要在對應的小程式回調中,調用 SDK 的 updatePlayerNetStatus 介面將推流網路事件透傳給 SDK。

// live-player 綁定網路狀態事件
onPlayNetStateChange(e) {
    // 透傳網路狀態事件給 SDK
    zg.updatePlayerNetStatus(playStreamID, e);
},

// SDK 拉流網路質量回調
zg.on("playQualityUpdate", (playStreamID, playStats) => {
    console.log("playQualityUpdate", playStreamID, playStats);
});

4.2 停止fang jian音視頻通話

4.2.1 停止推送/拉取音視頻流

1. 停止推流

調用 SDK 的 getPusherInstance 介面獲取推流實例,並調用推流實例的 stop 方法停止推流。

// 停止推流
zg.getPusherInstance().stop();

2. 停止拉流

調用 SDK 的 getPlayerInstance 介面獲取拉流實例,並調用推流實例的 stop 方法停止拉流。

// 停止拉流
zg.getPlayerInstance(streamID).stop();

4.2.2 退出房間

調用 SDK 的 logoutRoom 介面退出房間。

zg.logoutRoom(roomID);

5 調試視頻通話功能

在真機中運行項目,運行成功後,可以看到本端視頻畫面。

為方便體驗,ZEGO 提供了一個 Web 端調試示例 ,在該頁面下,輸入相同的 AppID、RoomID,輸入一個不同的 UserID,即可加入同一房間與真機設備互通。當成功開始音視頻通話時,可以聽到遠端的音頻,看到遠端的視頻畫面。

6 視頻通話 API 調用時序

整個推拉流過程的 API 調用時序可參考下圖:
下載5.png

音視頻場景解決方案分享,更多詳情可搜索官網(https://zegoguanwang.datasink.sensorsdata.cn/t/pB)
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • AU上傳ipa出現下圖紅框提示說明成功上傳,如果App Store後臺沒有出現構建版本, 請登錄 apple賬號對應的郵箱查看反饋,特別留意垃圾郵箱,無論成功還是失敗,apple都會發郵件 一、首先登錄iTunes Connect 後臺、查看ipa構建情況 https://appstoreconne ...
  • 現如今,人們在網上聊天、發帖時越來越愛用表情包,表情包一方面是一種個性化的表達方式,另一方面更能傳達出當下的心理活動,可以說在網路社交中表情包是一個不可或缺的存在。加上近年來元宇宙的興起,3D虛擬形象廣泛應用,用戶可以通過自己的表情來控制虛擬形象的表情,做一系列專屬的表情包,更加生動形象。 那麼,如 ...
  • ##vue+element-ui後臺管理系統模板 前端:基於vue2.0+或3.0+加上element-ui組件框架 後端:springboot+mybatis-plus寫介面 通過Axios調用介面完成數據傳遞 通過router路由完成各頁面的跳轉 ###全局配置 App.vue <templat ...
  • 好家伙,繼續優化, 好家伙,我把我的飛機大戰發給我的小伙伴們玩 期待著略微的贊賞之詞,然後他們用手機打開我的給他們的網址 然後點一下飛機就炸了。 游戲體驗零分 (滑鼠點擊在移動端依舊可以生效) 好了所以我們來優化一下這個觸屏移動事件 由於沒有參考,就去翻文檔了 觸摸事件分三個:touchstart、 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 1. 定義整體結構 先寫出構造函數,將Promise向外暴露 /* 自定義Promise函數模塊:IIFE */ (function (window) { /* Promise構造函數 executor:執行器函數 */ function ...
  • 一.分類 1.1 頁面佈局 首先創建cate的分支 定義基本結構,因為是兩個需要滾動的區域,所以這裡要用到組件 ==scroll== 這個組件如果是y scroll那就要固定高度,x scroll那就要固定寬度 這裡有個問題就是,我們應該把高度限定在整個屏幕高度 這裡用到uniapp一個api == ...
  • 每日3題 1 以下代碼執行後,控制臺中的輸出內容為? class A { static a = "123"; } class B extends A {} console.log(B.a); 2 以下3句語句,哪句是合法的 1.toString(); 1..toString(); 1...toStr ...
  • 1. 安裝sass 較新的版本不需要配置sass-loader等一系列插件,安裝即用。 npm install --save-dev sass 2. 編寫App.tsx中的基本DOM 更改app.css為app.scss,並刪除其中全部內容 使用如下代碼替換app.tsx中的內容 import ". ...
一周排行
    -Advertisement-
    Play Games
  • C#.Net的BCL提供了豐富的類型,最基礎的是值類型、引用類型,而他們的共同(隱私)祖先是 System.Object(萬物之源),所以任何類型都可以轉換為Object。 ...
  • 最近有群友咨詢C#如何調用Python?小編嘗試Python.NET過程中遭遇的版本相容性和環境配置難題,小編決定尋找一個更為簡單、穩定且對初學者友好的解決方案。小編搜索一番,除了Python.NET之外,還有其他途徑能夠幫助我們輕鬆地在C#項目調用Python腳本,那就是通過命令行調用,使用 Sy ...
  • .NET中特性+反射 實現數據校驗 在.NET中,我們可以使用特性+反射來實現數據校驗。特性是一種用於為程式中的代碼添加元數據的機制。元數據是與程式中的代碼相關聯的數據,但不直接成為代碼的一部分。通過特性,我們可以為類、方法、屬性等添加額外的信息,這些信息可以在運行時通過反射獲取和使用。 對反射不太 ...
  • Biwen.Settings 是一個簡易的配置項管理模塊,主要的作用就是可以校驗並持久化配置項,比如將自己的配置存儲到資料庫中,JSON文件中等 使用上也是很簡單,只需要在服務中註入配置, 比如我們有一個GithubSetting的配置項,我們只需要定義好對象然後註入到Service中即可: [De ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 前言 VB.NET,全名Visual Basic .NET,是Microsoft .NET框架的一部分,是一種面向對象的編程語言。它繼承了Visual Basic的易用性,同時增加了對面向對象編程的支持。VB.NET提供了大量的內置函數,使得開發者可以更容易地處理字元串、數學計算、文件和目錄訪問等任 ...
  • 自定義可移動點二維坐標軸控制項 目錄 路由參數 坐標軸控制項定義 Demo 路由參數 X_YResultCollection為當前X軸對應Y軸值存儲字典 public class ResultCollectionChangedEventArgs(RoutedEvent routedEvent, obje ...
  • 自定義分頁控制項 tip: 該控制項的樣式用的是materialDesign庫,需要下載Nuget包 Code Xaml <UserControl x:Class="TestTool.CustomControls.PagingControl" xmlns="http://schemas.microsof ...
  • 最近群里有個小伙伴把Dapper遷移SqlSugar幾個不能解決的問題進行一個彙總,我正好寫一篇文章來講解一下 一、sql where in傳參問題: SELECT * FROM users where id IN @ids 答: SqlSugar中應該是 var sql="SELECT * FRO ...
  • 安裝nuget包 Wesky.Net.OpenTools 1.0.8或以上版本。支持.net framework 4.6以上版本,以及所有.net core以及以上版本引用。 開發一個簡單的Winform界面,用來測試使用。如需該winform的demo,可以在公眾號【Dotnet Dancer】後 ...