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.GoodsTypes that.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; } } } }
运行结果:
![](/i/l/?n=23&i=blog/1101861/202302/1101861-20230207211308438-211271651.png)
标签:goods,exc,get,十三,WebView2,goodses,new,public,WinForm From: https://www.cnblogs.com/ljknlb/p/17099851.html