[WPF WebBrowser] C#에서 자바스크립트 함수를 호출하거나 자바스크립트에서 C# 메소드를 호출하는 방법
2022.08.03 - [C#/WinForm] - WebBrowser 자바스크립트에서 C# 메소드를 호출하는 방법
WebBrowser 자바스크립트에서 C# 메소드를 호출하는 방법
namespace WindowsFormsApplication6 { // This first namespace is required for the ComVisible attribute used on the ScriptManager class. using System.Runtime.InteropServices; using System.Windows.Forms; // This is your form. public partial class Form1 : Form
jasmintime.com
WPF에서는 뷰와 뷰모델을 분리하여 호출하는 방법에 대해 기술합니다.
1. 프로젝트를 생성합니다.
닷넷프레임워크 버전은 WPF 앱(.NET Framework) 선택
닷넷5, 6, 7 버전은 WPF 애플리케이션 선택
2. [도구]-[NuGet 패키지 관리자]-[솔루션용 NuGet 패키지 관리]에 들어갑니다.
3. Microsoft.XamlBehaviors.Wpf를 검색하여 설치합니다.
참고로 Microsoft.XamlBehaviors.Wpf는 닷넷프레임워크의 경우 4.5이상부터 되므로 닷넷프레임워크 4.0이면 System.Windows.Interactivity를 검색하여 설치합니다.
4. 사용자 정의 컨트롤(UserControl)를 추가합니다.
UCWebBrowser 명으로 추가하였습니다.
5. UCWebBrowser.xaml
<UserControl x:Class="WPF_Webbrowser.UCWebbrowser"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<WebBrowser x:Name="WebBrowserMain" Navigating="WebBrowserMain_Navigating" />
</Grid>
</UserControl>
6. UCWebBrowser.xaml.cs
using Microsoft.Win32;
using System;
using System.Reflection;
using System.Security.Permissions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace WPF_Webbrowser
{
/// <summary>
/// UCWebbrowser.xaml에 대한 상호 작용 논리
/// </summary>
public partial class UCWebbrowser : UserControl
{
public event EventHandler<MyEventArgs> OnGetJavastriptText;
/// <summary>
/// Map Url이 로드 되었는지 여부 입니다.
/// </summary>
public bool IsMapLoaded
{
get { return (bool)GetValue(IsMapLoadedProperty); }
set { SetValue(IsMapLoadedProperty, value); }
}
/// <summary>
/// WebBrowser에서 표시할 Map Url 입니다.
/// </summary>
public string MapUrl
{
get { return (string)GetValue(MapUrlProperty); }
set { SetValue(MapUrlProperty, value); }
}
/// <summary>
/// WebBrowser에서 실행할 Script 입니다. 할당 될 때마다 실행합니다.
/// </summary>
public string ExecuteScript
{
get { return (string)GetValue(ExecuteScriptProperty); }
set { SetValue(ExecuteScriptProperty, value); }
}
/// <summary>
/// WebBrowser에서 전달되는 데이터를 받기 위한 것 입니다.
/// </summary>
public MyEventArgs MyEventArgs
{
get { return (MyEventArgs)GetValue(MyEventArgsProperty); }
set { SetValue(MyEventArgsProperty, value); }
}
public static readonly DependencyProperty IsMapLoadedProperty =
DependencyProperty.Register("IsMapLoaded", typeof(bool), typeof(UCWebbrowser), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty MapUrlProperty =
DependencyProperty.Register("MapUrl", typeof(string), typeof(UCWebbrowser), new PropertyMetadata(string.Empty, MapUrlChanged));
public static readonly DependencyProperty ExecuteScriptProperty =
DependencyProperty.Register(
"ExecuteScript",
typeof(string),
typeof(UCWebbrowser),
new PropertyMetadata(ExecuteScriptChanged));
public static readonly DependencyProperty MyEventArgsProperty =
DependencyProperty.Register("MyEventArgs", typeof(MyEventArgs), typeof(UCWebbrowser), new PropertyMetadata(null));
private static void MapUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as UCWebbrowser;
if (e.NewValue == null || string.IsNullOrEmpty(e.NewValue.ToString()))
{
return;
}
control.WebBrowserMain.Navigate(e.NewValue.ToString());
}
private static void ExecuteScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as UCWebbrowser;
if (e.NewValue == null)
{
return;
}
if (e.NewValue != null && string.IsNullOrEmpty(e.NewValue.ToString()))
{
return;
}
if (control.IsMapLoaded)
{
control.ExecuteJavaScript(control.WebBrowserMain, e.NewValue.ToString());
}
}
public JavaScriptFuntion javaScriptFuntion;
public UCWebbrowser()
{
InitializeComponent();
SetUserAgent();
javaScriptFuntion = new JavaScriptFuntion();
javaScriptFuntion.OnMessageBoxShow += JavaScriptFuntion_OnMessageBoxShow;
WebBrowserMain.ObjectForScripting = javaScriptFuntion;
}
private void WebBrowserMain_Navigating(object sender, NavigatingCancelEventArgs e)
{
IsMapLoaded = true;
dynamic activeX = WebBrowserMain.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic
, null, WebBrowserMain, new object[] { });
activeX.Silent = true;
}
private void JavaScriptFuntion_OnMessageBoxShow(object sender, EventArgs e)
{
var data = sender.ToString();
MyEventArgs = new MyEventArgs(data);
OnGetJavastriptText?.Invoke(this, MyEventArgs);
}
/// <summary>
/// WebBrowser에서 스크립트를 실행합니다.
/// </summary>
/// <param name="web"></param>
/// <param name="script"></param>
private void ExecuteJavaScript(WebBrowser web, string script)
{
try
{
Console.WriteLine("ExecuteJavaScript : {0}", script);
Task.Factory.StartNew(delegate
{
Application.Current.Dispatcher.Invoke((Action)delegate
{
web.InvokeScript("execScript", new object[] { script, "JavaScript" });
});
});
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
javaScriptFuntion.OnMessageBoxShow -= JavaScriptFuntion_OnMessageBoxShow;
WebBrowserMain.Dispose();
}
/// <summary>
/// WebBrowser가 사용하는 IE 엔진이 구버전일 때 스크립트 오류 발생 방지를 위한
/// WebBrowser가 사용하는 IE 엔진이 최신 버전으로 갱신될 수 있게 UserAgent 속성을 설정
/// </summary>
private void SetUserAgent()
{
string regPath = @"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
string programName = System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe";
try
{
using (var regKey = Registry.CurrentUser.OpenSubKey(regPath, true))
{
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer"))
{
string version = key.GetValue("svcVersion").ToString();
int ieVersion = 0;
if (version.StartsWith("11."))
{
ieVersion = 11001;
}
else if (version.StartsWith("10."))
{
ieVersion = 10001;
}
else if (version.StartsWith("9."))
{
ieVersion = 9999;
}
else
{
Console.WriteLine("현재 시스템에는 웹브라우저를 업그레이드 할 수 없습니다.");
}
// 키가 이미 등록되어 있는지 확인 후 등록
if (regKey.GetValue(programName) == null && ieVersion > 0)
{
regKey.SetValue(programName, ieVersion, RegistryValueKind.DWord);
}
key.Close();
}
regKey.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
/// <summary>
/// 자바스크립트에서 실행 가능한 C#의 메소드를 정의
/// </summary>
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisible(true)]
public class JavaScriptFuntion
{
public event EventHandler OnMessageBoxShow;
public void MessageBoxShow(string text)
{
if (string.IsNullOrEmpty(text))
{
text = "";
}
OnMessageBoxShow?.Invoke(text, null);
}
}
public class MyEventArgs : EventArgs
{
public string Data { get; set; }
public MyEventArgs(string data)
{
Data = data;
}
}
}
7. MainWindow.xaml
<Window x:Class="WPF_Webbrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_Webbrowser"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:vm="clr-namespace:WPF_Webbrowser.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Width="245" Height="30" HorizontalAlignment="Left" Text="{Binding InputText, UpdateSourceTrigger=LostFocus}" />
<Button Grid.Column="1" Width="300" Height="30" HorizontalAlignment="Center" Command="{Binding ButtonCommand}" CommandParameter="ToJavaStript" Content="javascript의 helloWorld 함수 호출" />
<local:UCWebbrowser x:Name="WebBrowserMain" Grid.Row="1" MapUrl="{Binding MapUrl}" ExecuteScript="{Binding ExecuteScript}" >
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="OnGetJavastriptText">
<behaviors:InvokeCommandAction Command="{Binding DataContext.MyEventCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding ElementName=WebBrowserMain, Path=MyEventArgs}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</local:UCWebbrowser>
</Grid>
</Window>
8. MainViewModel.cs
using System;
using System.Windows;
using System.Windows.Input;
using WPF_Webbrowser.Models;
namespace WPF_Webbrowser.ViewModels
{
public class MainViewModel : NotifyPropertyChanged
{
private ICommand _ButtonCommand;
private ICommand _MyEventCommand;
private string _MapUrl;
private string _ExecuteScript;
private string _InputText;
public string MapUrl
{
get { return _MapUrl; }
set
{
_MapUrl = value;
OnPropertyChanged();
}
}
public string ExecuteScript
{
get { return _ExecuteScript; }
set
{
_ExecuteScript = value;
OnPropertyChanged();
}
}
public string InputText
{
get { return _InputText; }
set
{
_InputText = value;
OnPropertyChanged();
}
}
public ICommand ButtonCommand
{
get
{
if (_ButtonCommand == null)
{
_ButtonCommand = new RelayCommand<string>(obj => ButtonAction(obj));
}
return _ButtonCommand;
}
}
public ICommand MyEventCommand
{
get
{
if (_MyEventCommand == null)
{
_MyEventCommand = new RelayCommand<MyEventArgs>(obj => MyEventAction(obj));
}
return _MyEventCommand;
}
}
public MainViewModel()
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"Resources\test.html";
Uri uri = new Uri(@"file:///" + path);
MapUrl = uri.ToString();
}
/// <summary>
/// ButtonCommand의 동작을 수행합니다.
/// </summary>
/// <param name="obj"></param>
protected void ButtonAction(string obj)
{
Console.WriteLine("ButtonAction : {0}", obj);
switch(obj)
{
case "ToJavaStript":
ExecuteScript = $"helloWorld('{InputText}');";
break;
}
}
/// <summary>
/// MyEventCommand의 동작을 수행합니다.
/// </summary>
/// <param name="obj"></param>
protected void MyEventAction(MyEventArgs obj)
{
MessageBox.Show(obj.Data);
}
}
}
9. test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>자바스크립트 ↔ C# 함수 호출 예제</title>
</head>
<body>
<input type="text" width=200 id="messageBox">
<input type="button" value="폼에서 메시지박스 띄우기" onclick="messageBoxShow()">
<script>
function helloWorld(message) {
alert(message);
}
function messageBoxShow()
{
var textBox = document.getElementById("messageBox").value;
window.external.messageBoxShow(textBox);
}
</script>
</body>
</html>
10. 실행 화면
웹에서 button 클릭 시 C#의 messageBoxShow 메소드를 호출합니다.
C#에서 Button 클릭 시 웹의 helloWorld 함수를 호출합니다.
GitHub - yoosple/WPFs
Contribute to yoosple/WPFs development by creating an account on GitHub.
github.com