WPF和web泛型通信

This commit is contained in:
ShaoHua
2026-03-11 22:25:30 +08:00
parent be9b042a05
commit 295a05d4ae
9 changed files with 506 additions and 70 deletions
+35 -67
View File
@@ -1,84 +1,52 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useAppLogic } from './AppLogic'
const receivedMsg = ref('等待消息...')
const inputMsg = ref('')
const handleMessage = (event) => {
console.log("收到来自 WPF 的消息:", event.data);
receivedMsg.value = event.data
}
onMounted(() => {
if (window.chrome && window.chrome.webview) {
window.chrome.webview.addEventListener('message', handleMessage)
}
})
onUnmounted(() => {
if (window.chrome && window.chrome.webview) {
window.chrome.webview.removeEventListener('message', handleMessage)
}
})
const sendMessageToWPF = () => {
if (window.chrome && window.chrome.webview) {
window.chrome.webview.postMessage(inputMsg.value)
} else {
alert('未在 WebView2 环境中运行')
}
}
// 所有的业务逻辑都在 AppLogic.js 中实现
const {
receivedMsg,
systemInfo,
calcResult,
fetchSystemInfo,
triggerNativeAlert,
runCalculation
} = useAppLogic()
</script>
<template>
<div class="container">
<h1>Vue 3 + WebView2 交互演示</h1>
<h1>WebView2 标准化交互网关</h1>
<div class="card">
<h3>接收来自 WPF 的消息:</h3>
<p class="msg-box">{{ receivedMsg }}</p>
<h3>1. 属性同步 (WebMessage)</h3>
<p>来自 WPF 的推送: {{ receivedMsg }}</p>
</div>
<div class="card">
<h3>发送消息给 WPF:</h3>
<input v-model="inputMsg" placeholder="输入消息" />
<button @click="sendMessageToWPF">发送到 WPF</button>
<h3>2. 动态 API 调用 (Host Objects + 信封)</h3>
<div class="btn-group">
<button @click="fetchSystemInfo">获取 C# 系统信息</button>
<button @click="triggerNativeAlert" class="btn-warning">触发原生弹窗</button>
<button @click="runCalculation" class="btn-info">计算 10 + 20</button>
</div>
<div v-if="systemInfo" class="result-box">
<b>系统信息:</b> {{ systemInfo.OS }} ({{ systemInfo.Runtime }})
</div>
<div v-if="calcResult !== null" class="result-box">
<b>计算结果:</b> {{ calcResult }}
</div>
</div>
</div>
</template>
<style scoped>
.container {
font-family: Arial, sans-serif;
padding: 20px;
text-align: center;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
background: #f9f9f9;
}
.msg-box {
font-weight: bold;
color: #2c3e50;
font-size: 1.2em;
}
input {
padding: 8px;
width: 200px;
margin-right: 10px;
}
button {
padding: 8px 15px;
background-color: #42b883;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #3aa876;
}
.container { padding: 20px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.card { border: 1px solid #eee; padding: 15px; margin-bottom: 15px; border-radius: 8px; background: #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
.btn-group { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
button { padding: 8px 16px; border: none; border-radius: 4px; background: #42b883; color: white; cursor: pointer; }
button:hover { background: #3aa876; }
.btn-warning { background: #f39c12; }
.btn-info { background: #3498db; }
.result-box { margin-top: 15px; padding: 10px; background: #f8f9fa; border-left: 4px solid #42b883; font-size: 0.9em; }
</style>
+60
View File
@@ -0,0 +1,60 @@
import { ref, onMounted } from 'vue'
import { InteropHelper } from './utils/interop'
/**
* App 页面的业务逻辑 Hook
*/
export function useAppLogic() {
const receivedMsg = ref('等待消息...')
const systemInfo = ref(null)
const calcResult = ref(null)
// 1. 获取系统信息 (演示带返回值的标准化调用)
const fetchSystemInfo = async () => {
try {
const data = await InteropHelper.callApi('GetSystemInfo')
systemInfo.value = data
} catch (err) {
alert('获取失败: ' + err.message)
}
}
// 2. 发送弹窗指令 (演示带参数的标准化调用)
const triggerNativeAlert = async () => {
try {
await InteropHelper.callApi('ShowDialog', '这是来自 Vue 的标准化信封消息!')
} catch (err) {
console.error('弹窗指令发送失败:', err)
}
}
// 3. 泛型计算演示 (演示复杂对象参数)
const runCalculation = async () => {
try {
const result = await InteropHelper.callApi('Calculate', { a: 10, b: 20 })
calcResult.value = result
} catch (err) {
console.error('计算失败:', err)
}
}
// 原有的 WebMessage 接收逻辑
const handleMessage = (event) => {
receivedMsg.value = event.data
}
onMounted(() => {
if (window.chrome && window.chrome.webview) {
window.chrome.webview.addEventListener('message', handleMessage)
}
})
return {
receivedMsg,
systemInfo,
calcResult,
fetchSystemInfo,
triggerNativeAlert,
runCalculation
}
}
+47
View File
@@ -0,0 +1,47 @@
/**
* 前后端互操作工具类
*/
export class InteropHelper {
/**
* 调用原生 API (通过 StandardApiRequest/Response 协议)
* @param {string} action 行为名称
* @param {any} data 业务数据
* @returns {Promise<any>}
*/
static async callApi(action, data = null) {
if (!window.chrome?.webview?.hostObjects?.gateway) {
const errorMsg = 'WebView2 环境未就绪 (hostObjects.gateway 缺失)';
console.error(errorMsg);
throw new Error(errorMsg);
}
const gateway = window.chrome.webview.hostObjects.gateway;
// 1. 封装标准信封
const requestEnvelope = {
action: action,
data: data
};
try {
// 2. 调用 C# 网关方法 (使用新的方法名 InvokeAction)
const responseJson = await gateway.InvokeAction(JSON.stringify(requestEnvelope));
console.log(`API [${action}] 原始响应:`, responseJson);
// 3. 解析标准回包
const response = JSON.parse(responseJson);
if (response.success) {
return response.data;
} else {
const errorMsg = response.message || '未知错误';
console.error(`API [${action}] 返回失败:`, errorMsg);
throw new Error(errorMsg);
}
} catch (err) {
console.error(`API 调用崩溃 [${action}]:`, err);
// 如果是在控制台看到的报错,通常是因为 C# 端发生了未捕获异常
throw err;
}
}
}