using Collections.Generic;
using Monaco.Editor;
using Monaco.Extensions;
using Monaco.Helpers;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The Templated Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234235
namespace Monaco
{
///
/// UWP Windows Runtime Component wrapper for the Monaco CodeEditor
/// https://microsoft.github.io/monaco-editor/
///
[TemplatePart(Name = "View", Type = typeof(WebView))]
public sealed partial class CodeEditor : Control, INotifyPropertyChanged
{
private bool _initialized;
private WebView _view;
private ModelHelper _model;
public event PropertyChangedEventHandler PropertyChanged;
///
/// Template Property used during loading to prevent blank control visibility when it's still loading WebView.
///
public bool IsLoaded
{
get { return (bool)GetValue(IsLoadedProperty); }
private set { SetValue(IsLoadedProperty, value); }
}
// Using a DependencyProperty as the backing store for HorizontalLayout. This enables animation, styling, binding, etc...
private static readonly DependencyProperty IsLoadedPropertyField =
DependencyProperty.Register("IsLoaded", typeof(string), typeof(CodeEditor), new PropertyMetadata(false));
public static DependencyProperty IsLoadedProperty
{
get
{
return IsLoadedPropertyField;
}
}
///
/// Construct a new IStandAloneCodeEditor.
///
public CodeEditor()
{
DefaultStyleKey = typeof(CodeEditor);
if (Options != null)
{
// Set Pass-Thru Properties
Options.GlyphMargin = HasGlyphMargin;
Options.Language = CodeLanguage;
// Register for changes
Options.PropertyChanged += Options_PropertyChanged;
}
// Initialize this here so property changed event will fire and register collection changed event.
Decorations = new ObservableVector();
Markers = new ObservableVector();
_model = new ModelHelper(this);
base.Loaded += CodeEditor_Loaded;
Unloaded += CodeEditor_Unloaded;
}
private async void Options_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// TODO: Check for Language property and call other method instead?
await InvokeScriptAsync("updateOptions", sender);
}
private void CodeEditor_Loaded(object sender, RoutedEventArgs e)
{
// Do this the 2nd time around.
if (_model == null && _view != null)
{
_model = new ModelHelper(this);
_parentAccessor = new ParentAccessor(this);
_parentAccessor.AddAssemblyForTypeLookup(typeof(Range).GetTypeInfo().Assembly);
_parentAccessor.RegisterAction("Loaded", CodeEditorLoaded);
_themeListener = new ThemeListener();
_themeListener.ThemeChanged += _themeListener_ThemeChanged;
_themeToken = RegisterPropertyChangedCallback(RequestedThemeProperty, RequestedTheme_PropertyChanged);
_keyboardListener = new KeyboardListener(this);
_view.AddWebAllowedObject("Parent", _parentAccessor);
_view.AddWebAllowedObject("Theme", _themeListener);
_view.AddWebAllowedObject("Keyboard", _keyboardListener);
Options.PropertyChanged += Options_PropertyChanged;
Decorations.VectorChanged += Decorations_VectorChanged;
Markers.VectorChanged += Markers_VectorChanged;
_view.NewWindowRequested += WebView_NewWindowRequested;
_initialized = true;
Loading?.Invoke(this, new RoutedEventArgs());
Unloaded += CodeEditor_Unloaded;
Loaded?.Invoke(this, new RoutedEventArgs());
}
}
private void CodeEditor_Unloaded(object sender, RoutedEventArgs e)
{
Unloaded -= CodeEditor_Unloaded;
if (_view != null)
{
_view.NavigationStarting -= WebView_NavigationStarting;
_view.DOMContentLoaded -= WebView_DOMContentLoaded;
_view.NavigationCompleted -= WebView_NavigationCompleted;
_view.NewWindowRequested -= WebView_NewWindowRequested;
_initialized = false;
}
Decorations.VectorChanged -= Decorations_VectorChanged;
Markers.VectorChanged -= Markers_VectorChanged;
_parentAccessor?.Dispose();
_parentAccessor = null;
Options.PropertyChanged -= Options_PropertyChanged;
_themeListener.ThemeChanged -= _themeListener_ThemeChanged;
_themeListener = null;
UnregisterPropertyChangedCallback(RequestedThemeProperty, _themeToken);
_keyboardListener = null;
_model = null;
}
protected override void OnApplyTemplate()
{
if (_view != null)
{
_view.NavigationStarting -= WebView_NavigationStarting;
_view.DOMContentLoaded -= WebView_DOMContentLoaded;
_view.NavigationCompleted -= WebView_NavigationCompleted;
_view.NewWindowRequested -= WebView_NewWindowRequested;
_initialized = false;
}
_view = (WebView)GetTemplateChild("View");
if (_view != null)
{
_view.NavigationStarting += WebView_NavigationStarting;
_view.DOMContentLoaded += WebView_DOMContentLoaded;
_view.NavigationCompleted += WebView_NavigationCompleted;
_view.NewWindowRequested += WebView_NewWindowRequested;
_view.Source = new Uri("ms-appx-web:///Monaco/MonacoEditor.html");
}
base.OnApplyTemplate();
}
internal async Task SendScriptAsync(string script,
[CallerMemberName] string member = null,
[CallerFilePath] string file = null,
[CallerLineNumber] int line = 0)
{
await SendScriptAsync