#c# #wpf #cefsharp
#c# #wpf #cefsharp
Вопрос:
Я работаю над приложением WPF с браузером CefSharp chromium. У меня есть TabControl, где каждый элемент вкладки содержит браузер chromium и содержит разные веб-сайты.
Проблема: я вижу пустой экран для одного веб-сайта в одном из элементов вкладки, тогда как тот же веб-сайт нормально загружается в автономном браузере (Google Chrome / Microsoft Edge).
Наблюдения / анализ: когда веб-сайт загружается в автономном браузере (Google Chrome / Microsoft Edge), я получаю всплывающее окно браузера с просьбой разрешить или заблокировать уведомления, НО я не получил это всплывающее окно в своем приложении. Когда я открыл инструменты разработки для конкретного браузера chromium в своем приложении, я обнаружил в консоли ошибку ниже: ОШИБКА ReferenceError: уведомление не определено
Я знаю, что мы можем разрешить или заблокировать микрофон / камеру из кода C #, как показано ниже:
CefSettings settings = new CefSettings();
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
Cef.Initialize(settings);
Есть ли какой-либо аргумент команды для разрешения / блокировки уведомлений, подобных приведенному выше коду?
Пожалуйста, помогите.
Комментарии:
1. Согласно magpcss.org/ceforum/viewtopic.php?f=6amp;t=16009 CEF не поддерживает API уведомлений. Вы можете создать полизаполнение JavaScript для добавления базовой поддержки. См . github.com/Haltroy/Korot/issues/22 для обсуждения этой темы.
Ответ №1:
CefSharp не поддерживает API уведомлений. https://github.com/cefsharp/CefSharp/issues/2890 Но вы можете сделать свою собственную реализацию. Используйте JavaScript, чтобы переопределить конструктор уведомлений и отправить сообщение из CefSharp в ваш код, предварительно упаковав его в JSON.
public void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
Browser.ExecuteScriptAsync(@"(function(){ class Notification {
static permission = 'granted';
static maxActions = 2;
static name = 'Notification';
constructor(title, options) {
let packageSet = new Set();
packageSet.add(title).add(options);
let json_package = JSON.stringify([...packageSet]);
CefSharp.PostMessage(json_package);
//alert(title);
}
static requestPermission() {
return new Promise((res, rej) => {
res('granted');
})
}
};
window.Notification = Notification;
})();");
}
Получите сообщение и поместите его в очередь. Я использовал Newtonsoft для распаковки из JSON.
private void OnBrowserJavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e)
{
object[] objArray = JsonConvert.DeserializeObject<object[]>(e.Message.ToString());
Options options = JsonConvert.DeserializeObject<Options>(objArray[1].ToString(), new ImageConverter());
// Add to Notification queue
MessageQueue.Enqueue(new object[] { objArray[0], options });
}
MessageQueue — это простая очередь объектов массива, которые мы затем обрабатываем в другом потоке.
public Queue<object[]> MessageQueue = new Queue<object[]>();
Структура уведомлений.
public class Options
{
public byte[] icon { get; set; }
public string body { get; set; }
public string tag { get; set; }
public bool canReply { get; set; }
public bool silent { get; set; }
public bool requireInteraction { get; set; }
}
Конвертер изображений
public class ImageConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(byte[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var str = reader.Value.ToString();
var index = reader.Value.ToString().IndexOf("base64,");
if (index == -1)
{
try
{
// Download the icon
Task<byte[]> task = App.ImageDownloaderObj.GetImageBytesAsync(new Uri(str));
task.Wait(500);
return task.Resu<
}
catch { return new byte[] { }; }
}
else
{
var m = new MemoryStream(Convert.FromBase64String(str.Substring(index 7)));
return m.ToArray();
}
//return (Bitmap)Image.FromStream(m);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Bitmap bmp = (Bitmap)value;
MemoryStream m = new MemoryStream();
bmp.Save(m, System.Drawing.Imaging.ImageFormat.Png);
writer.WriteValue(Convert.ToBase64String(m.ToArray()));
}
}
Комментарии:
1. Несколько комментариев, JavascriptMessageReceived вызывается в пуле потоков, поэтому вызывается MessageBox. Показывать не рекомендуется, поскольку цикл сообщений не выполняется, лучше всего использовать поток пользовательского интерфейса для всего, что связано с пользовательским интерфейсом. Было бы здорово, если бы пример действительно отправлял текст уведомления, а не фиксированную строку.
2. Спасибо за комментарий, я внес изменения. Теперь это код, фактически запущенный в одном из проектов.