【WPF】嵌入Web网页的一些总结

一、嵌入技术

网上有很多嵌入的解决方案,这边记录一个整理较好的网站https://www.cnblogs.com/SavionZhang/p/15169863.html

二、开发实现中遇到的一些问题整理

1.WPF嵌入Web后不显示问题

我自己测试了chrome内核和ie内核去加载Web,ChromiumWebBrowser不存在该问题。这里针对IE内核,也就是WPF自带的Web嵌入组件WebBrowser,在实现窗口自定义的时候,会让网页不显示的问题做出解决方案。一般我们的创久自定义都会设置WindowStyle="None" AllowsTransparency="True",问题就在AllowsTransparency这个窗口属性上,当我们将它设置为true,因为WPF的渲染绘制机制会绘制不出加载的Web页面(内容有但是没有UI)。因此这里需要这样设置WindowStyle="None" AllowsTransparency="False" ResizeMode="CanMinimize" ,AllowsTransparency=“False” 时会是我们的窗口自定义样式出现原本窗口的背景,这个时候就需要ResizeMode=“CanMinimize”。但同时,也会让自己的窗口无法拖拽大小。这里可以自己去实现以下拖拽大小的代码:
在窗口的最外层增加一圈

        <Grid.RowDefinitions>
            <RowDefinition Height="5"/>
            <RowDefinition/>
            <RowDefinition Height="5"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="5"/>
        </Grid.ColumnDefinitions>

然后在定义的这一圈上加上

        <Rectangle Name="ResizeTopLeft" Fill="Transparent" Grid.Row="0" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeTop" Fill="Transparent" Grid.Row="0" Grid.Column="1" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeTopRight" Fill="Transparent" Grid.Row="0" Grid.Column="2" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeLeft" Fill="Transparent" Grid.Row="1" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeRight" Fill="Transparent" Grid.Row="1" Grid.Column="3" MouseMove="ResizePressed" MouseDown="ResizePressed" Margin="0 0 -5 0"/>
        <Rectangle Name="ResizeBottomLeft" Fill="Transparent" Grid.Row="3" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeBottom" Fill="Transparent" Grid.Row="3" Grid.Column="1" MouseMove="ResizePressed" MouseDown="ResizePressed"/>
        <Rectangle Name="ResizeBottomRight" Fill="Transparent" Grid.Row="3" Grid.Column="2" MouseMove="ResizePressed" MouseDown="ResizePressed"/>

对应的响应方法为:

        public HwndSource _HwndSource;
        private const int WM_SYSCOMMAND = 0x112;
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private Dictionary<ResizeDirection, Cursor> cursors = new Dictionary<ResizeDirection, Cursor>
        {
            {ResizeDirection.Top, Cursors.SizeNS},
            {ResizeDirection.Bottom, Cursors.SizeNS},
            {ResizeDirection.Left, Cursors.SizeWE},
            {ResizeDirection.Right, Cursors.SizeWE},
            {ResizeDirection.TopLeft, Cursors.SizeNWSE},
            {ResizeDirection.BottomRight, Cursors.SizeNWSE},
            {ResizeDirection.TopRight, Cursors.SizeNESW},
            {ResizeDirection.BottomLeft, Cursors.SizeNESW}
        };

        void Window_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                if (Mouse.LeftButton != MouseButtonState.Pressed)
                {
                    FrameworkElement element = e.OriginalSource as FrameworkElement;
                    if (element != null && !element.Name.Contains("Resize")) this.Cursor = Cursors.Arrow;
                }
            }
            catch (Exception ex)
            {
                LogOutput.WriteErrorLog("Window_MouseMove error : " + ex.Message);
            }
        }

        private void ResizePressed(object sender, MouseEventArgs e)
        {

            try
            {
                FrameworkElement element = sender as FrameworkElement;
                ResizeDirection direction = (ResizeDirection)Enum.Parse(typeof(ResizeDirection), element.Name.Replace("Resize", ""));

                this.Cursor = cursors[direction];
                if (e.LeftButton == MouseButtonState.Pressed) ResizeWindow(direction);
            }
            catch (Exception ex)
            {
                LogOutput.WriteErrorLog("ResizePressed Move error : " + ex.Message);
            }
        }

        private void ResizeWindow(ResizeDirection direction)
        {
            try
            {
                var _vm = this.DataContext as AppStoreUIViewModel;
                var handle = AppStoreUIViewModel.FindWindow(null, "uMRAppStore");
                SendMessage(handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
            }
            catch (Exception ex)
            {
                LogOutput.WriteErrorLog("ResizeWindow error : " + ex.Message);
            }
        }

        private void ResizePressed(object sender, MouseButtonEventArgs e)
        {
            try
            {
                FrameworkElement element = sender as FrameworkElement;
                ResizeDirection direction = (ResizeDirection)Enum.Parse(typeof(ResizeDirection), element.Name.Replace("Resize", ""));

                this.Cursor = cursors[direction];
                if (e.LeftButton == MouseButtonState.Pressed) ResizeWindow(direction);
            }
            catch(Exception ex)
            {
                LogOutput.WriteErrorLog("ResizePressed Btn error : " + ex.Message);
            } 
        }

可见IE的繁琐性,所以还是建议使用Chorme,如果平台不做限制,可以使用较新的EDGE的内核控件。

2.WEB安全策略报错以及弹框

因项目限制,所以我后面用的都是IE内核的。在使用的过程中发现,加载网页后,会出像两个问题。
一个是安全协议报错。这里我才去的是跳过策略校验。增加辅助类:

    public static class WebBrowserExtensions
    {
        /// <summary>
        /// 过滤网页加载错误信息弹窗
        /// </summary>
        /// <param name="webBrowser"></param>
        /// <param name="hide"></param>
        public static void SuppressScriptErrors(this WebBrowser webBrowser, bool hide)
        {
            try
            {
                FieldInfo fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
                if (fiComWebBrowser == null) return;

                object objComWebBrowser = fiComWebBrowser.GetValue(webBrowser);
                if (objComWebBrowser == null) return;

                objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { hide });
            }
            catch(Exception ex)
            {
                LogOutput.WriteErrorLog("SuppressScriptErrors error : " + ex.Message);
            }
        }
    }

在每个加载网页的地方 WebBrowserExtensions.SuppressScriptErrors(AppStoreWindow.detial.wb, true);
另一个问题就是会弹出“安全警报”窗口,这里我的处理是增加一个定时器,在弹出时进行快速关闭:

                timerCheckWebAlert.Interval = 20;
                timerCheckWebAlert.Enabled = true;
                timerCheckWebAlert.Elapsed += new System.Timers.ElapsedEventHandler(TimerCheckWebAlert_Elapsed);
        //使用定时器来检查是否出现窗口,如果有就关闭
        private void TimerCheckWebAlert_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            IntPtr hwnd = FindWindow(null, "安全警报");
            if (hwnd != IntPtr.Zero)
            {
                IntPtr btnhwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "是(&Y)");
                if (btnhwnd != IntPtr.Zero)
                {
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);//先移上去
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);//再点击
                }
            }
            IntPtr hwndweb = FindWindow(null, "Web 浏览器");
            if (hwndweb != IntPtr.Zero)
            {
                IntPtr btnhwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "是(&Y)");
                if (btnhwnd != IntPtr.Zero)
                {
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);
                }
            }
            IntPtr hwndEn = FindWindow(null, "security alert");
            if (hwndEn != IntPtr.Zero)
            {
                IntPtr btnhwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "是(&Y)");
                if (btnhwnd != IntPtr.Zero)
                {
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);
                    SendMessage(btnhwnd, WM_CLICK, 0, 0);
                }
            }
        }

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        private int WM_CLICK = 0x00F5;
        [System.Runtime.InteropServices.DllImport("user32")]
        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        //移动鼠标 
        public const int MOUSEEVENTF_MOVE = 0x0001;
        //模拟鼠标左键按下 
        public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        //模拟鼠标左键抬起 
        public const int MOUSEEVENTF_LEFTUP = 0x0004;
        //模拟鼠标右键按下 
        public const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        //模拟鼠标右键抬起 
        public const int MOUSEEVENTF_RIGHTUP = 0x0010;
        //模拟鼠标中键按下 
        public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        //模拟鼠标中键抬起 
        public const int MOUSEEVENTF_MIDDLEUP = 0x0040;
        //标示是否采用绝对坐标 
        public const int MOUSEEVENTF_ABSOLUTE = 0x8000;
        [DllImport("user32.dll")]
        public static extern bool SetCursorPos(int X, int Y);
        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
        public static extern bool SetF(IntPtr hWnd); //设置此窗体为活动窗体

3.Chorme内核无法支持多格式播放视频

这里也是在GitHub上看到了一个大神自己重构了一下CefSharp的库,直接替换本地的packages下就可以了。
这里GitHub上的包下了,大家可以尝试再去找找。这里有个CSDN的包,大家可以尝试。https://blog.csdn.net/ldy597321444/article/details/84677752?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-9-84677752-blog-120221096.pc_relevant_3mothn_strategy_and_data_recovery&spm=1001.2101.3001.4242.6&utm_relevant_index=12

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值