WebView是WinForm框架中一個控件,用來對網頁信息交互,有時Web自己開發的,有時Web是三方的。
下面通過一個例子來看看WebView2的使用。
首先看Web的邏輯,是一個商品添加頁面,用AlpineJS和BootStrap來開發的,業務上點擊添加按鈕,彈出modal框窗,然后保存結果,完成添加,代碼如下:
View
@{ViewData["Title"] = "商品管理";
}
@section Css{<style>.form-switch {display: flex !important;flex-direction: row-reverse !important;justify-content: space-between !important;}
</style>
}
<div x-data="querydata()" id="ttt"><div class="row" style="margin:4px"><div class="col-sm-4"></div><div class="col-sm-4"></div><div class="col-sm-4" style="text-align:right" style="margin:4px 0px"><button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#addgoods">追加</button></div></div><hr /><div class="mb-3 row"><table class="table table-striped"><thead><tr><th>ID</th><th>名前</th><th>価格</th><th>説明</th><th>有効</th><th>シリアル番號</th><th>製品タイプ</th><th>操作</th></tr></thead><tbody><template x-for="goods in Goodses"><tr><td x-text="goods.ID"></td><td x-text="goods.Name"></td><td x-text="goods.Price"></td><td x-text="goods.Describe"></td><td x-text="goods.Validate"></td><td x-text="goods.SerialNumber"> </td><td x-text="goods.GoodsType"></td><td><button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#modifygoods" x-on:click="modify(goods)">改訂</button><button type="button" class="btn btn-danger btn-sm" x-on:click="remove(goods.ID)">消去</button></td></tr></template></tbody></table></div><div class="modal fade" id="addgoods" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title" id="staticBackdropLabel"> 追加Goods</h5><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div><div class="modal-body"><div class="container-fluid"><div class="mb-3 row"><label for="GoodsTypeID" class="col-sm-4 col-form-label">Goodsタイプ</label><div class="col-sm-8"><select class="form-select" x-model="Goods.GoodsTypeID" id="GoodsTypeID" aria-label="Default select example"><option selected>製品タイプ</option><template x-for="(item,index) in GoodsTypes" :key="index"><option x-text="item.Name" :value="item.ID"></option></template></select></div></div><div class="mb-3 row"><label for="name" class="col-sm-4 col-form-label">お名前</label><div class="col-sm-8"><input type="text" class="form-control" x-model="Goods.Name" placeholder="" id="Name"></div></div><div class="mb-3 row"><label for="Price" class="col-sm-4 col-form-label">価格</label><div class="col-sm-8"><input type="number" class="form-control" x-model="Goods.Price" placeholder="" min="1" id="Price"></div></div><div class="mb-3 row"><label for="Describe" class="col-sm-4 col-form-label">説明</label><div class="col-sm-8"><input type="text" class="form-control" x-model="Goods.Describe" placeholder="" min="1" id="Describe"></div></div><div class="mb-3 row"><label for="SerialNumber" class="col-sm-4 col-form-label">シリアル番號</label><div class="col-sm-8"><input type="number" class="form-control" x-model="Goods.SerialNumber" placeholder="" min="1" id="SerialNumber"></div></div><div class="form-check form-switch mb-3 row" style="margin-left:150px"><label class="form-check-label" for="IsCollapse">有効</label><input class="form-check-input" type="checkbox" role="switch" x-model="Goods.Validate" id="Validate" checked></div><div></div></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉鎖</button><button type="button" class="btn btn-primary" data-bs-dismiss="modal" x-on:click="sava">保存</button></div></div></div></div></div>@section Scripts{<script src="~/js/Alpine.js" defer></script><script>function querydata() {return {GoodsTypes: [],Goodses: [],Goods: {Name: '',Price: 0,Describe: '',Validate: true,SerialNumber: 0,GoodsTypeID: 0,GoodsType: '',},init() {that = this$.get("/home/goodses", {}, function (data) {if (data != null) {that.GoodsTypes = data.Data.GoodsTypesthat.Goodses = data.Data.Goodses} else {console.log("/Home/Goodses is error")}});},sava() {$.ajax({type: "POST",url: "/home/goods",data: this.Goods,success: function (data) {if (data.Result) {alert("送信に成功!")that.init()that.Goods = {Name: '',Price: 0,Describe: '',Validate: true,SerialNumber: 0,GoodsTypeID: 0,GoodsType: '',}} else {alert("提出に失敗しました:" + data.Message)}}});}}}
</script>}
</div>
Controller
using Microsoft.AspNetCore.Mvc;
using System.Collections.Immutable;
using System.Diagnostics;
using WinFormDemo12WebHost.Models;namespace WinFormDemo12WebHost.Controllers
{public class HomeController : Controller{private readonly ILogger<HomeController> _logger;public HomeController(ILogger<HomeController> logger){_logger = logger;}public?IActionResult?Goods(){return View();}static List<GoodsType> _goodsTypes = new List<GoodsType> {new GoodsType {ID=1,Name="A類型" },new GoodsType {ID=2,Name="B類型" },};static List<Goods> _goodses = new List<Goods>{};[HttpGet("/home/goodses")]public async Task<JsonResult?> QueryGoodsesAsync(){try{_logger.LogInformation("BackQuery Goods List");var goodsTypes = _goodsTypes;var goodses = _goodses;return new JsonResult(new{Data = new{GoodsTypes = goodsTypes,Goodses = goodses}});}catch (Exception exc){_logger.LogCritical(exc, exc.Message);return new JsonResult(new{Result = false,Message = exc.Message});}}[HttpDelete("/home/goods")]public async Task<JsonResult?> DeleteGoodsAsync(int id){try{_logger.LogInformation("delete goods");var result = _goodses.Remove(_goodses.SingleOrDefault(s => s.ID == id));return new JsonResult(new{Result = result});}catch (Exception exc){_logger.LogCritical(exc, exc.Message);return new JsonResult(new { Result = false, Message = exc.Message });}}[HttpPut("/home/goods")]public async Task<JsonResult?> ModifyGoodsAsync(Goods goods){try{_logger.LogInformation("modify goods");_goodses.Remove(_goodses.SingleOrDefault(s => s.ID == goods.ID));goods.ID = _goodses.Max(s => s.ID) + 1;_goodses.Add(goods);return new JsonResult(new{Result = goods});}catch (Exception exc){_logger.LogCritical(exc, exc.Message);return new JsonResult(new { Result = false, Message = exc.Message });}}[HttpPost("/home/goods")]public async Task<JsonResult?> AddGoodstAsync(Goods goods){try{_logger.LogInformation("add goods");goods.ID = _goodses.Count > 0 ? _goodses.Max(s => s.ID) + 1 : 1;_goodses.Add(goods);return new JsonResult(new{Result = true,Data = goods});}catch (Exception exc){_logger.LogCritical(exc, exc.Message);return new JsonResult(new { Result = false, Message = exc.Message });}}???}public class GoodsType{public int ID { get; set; }public string? Name { get; set; }}public class Goods{public int ID { get; set; }public string? Name { get; set; }public decimal Price { get; set; }public string? Describe { get; set; }public?bool?Validate?{?get;?set;?}public?int?GoodsTypeID?{?get;?set;?}public int SerialNumber { get; set; }public string GoodsType { get; set; }public decimal MaxPrice{get{return Price >= 70000 ? Price + 3000 : (Price > 0 ? Price + 2000 : 0);}}public decimal MinPrice{get{return Price >= 70000 ? Price - 3000 : (Price > 2000 ? Price - 2000 : 0);}}}
}
WebView2與控件與Web的交互主要通過webView21.CoreWebView2.ExecuteScriptAsync方法完成,所以不同的Web內容,JS的寫法不一樣,當然這里的JS實現簡單交互還行,更復雜的就有點吃力了,可以使用一些UI自動化工庫來操作更快捷。在WinForm中使用WebView,更多的是用來展現數據,而不是互操作,所以下面只是一個簡單交互例子而已。
下面是模擬三個動作:點擊添加按鈕,在商品添加頁面中完成信息錄入,然后點擊保存按鈕(即使保存成功或失敗后的alter也能針對處理)。
using System.Collections.Generic;namespace WinFormsDemo13
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){webView21.Source = new Uri(@"http://localhost:5026/home/goods");}private void button1_Click(object sender, EventArgs e){var js = """$(".btn-info").click()""";webView21.CoreWebView2.ExecuteScriptAsync(js);}int sn = 1;private void button2_Click(object sender, EventArgs e){int mark = DateTime.Now.Millisecond * 1000 + DateTime.Now.Microsecond;var js = $""" var goods=document.querySelector('[x-data]')._x_dataStack[0].Goods;goods.GoodsTypeID={mark % 2 + 1};goods.Name="商品{mark}";goods.Price={100 * new Random().Next(1, 20)};goods.Describe="商品{mark}說明";goods.SerialNumber={sn};goods.Validate={(mark % 2 == 0).ToString().ToLower()};goods.GoodsType="{(mark % 2 == 0 ? "A類型" : "B類型")}";""";webView21.CoreWebView2.ExecuteScriptAsync(js);sn++;}private void button3_Click(object sender, EventArgs e){var js = """$("#addgoods .btn-primary").click()""";webView21.CoreWebView2.ExecuteScriptAsync(js);} private void CoreWebView2_ScriptDialogOpening(object? sender, Microsoft.Web.WebView2.Core.CoreWebView2ScriptDialogOpeningEventArgs e){e.Accept();}private void webView21_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e){if (e.IsSuccess){webView21.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;webView21.CoreWebView2.ScriptDialogOpening += CoreWebView2_ScriptDialogOpening;}}}
}
運行結果: