Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions applications/lokqlDx/ViewModels/RenderingSurfaceViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,18 @@ public void CopyToClipboard()
ChartModel.CopyToClipboard();
}

private Task RenderTable(KustoQueryResult result)
private async Task RenderTable(KustoQueryResult result)
{
//ensure that if there are no results we clear the data grid
if (result.Error.IsNotBlank())
{
var errorRows = new[] { new Row([result.Error]) };
var columnList = new ColumnList<Row> { new TextColumn<Row, object?>("Error", r => r[0]) };
TreeSource = new MyFlatTreeDataGridSource<Row>(errorRows, columnList);
return Task.CompletedTask;
return;
}

DispatcherHelper.SafeInvoke(() =>
await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
{
const int defaultMax = 10000;
const string settingName = "datagrid.maxrows";
Expand All @@ -195,8 +195,6 @@ private Task RenderTable(KustoQueryResult result)
source.Selection = new TreeDataGridCellSelectionModel<Row>(source);
TreeSource = source;
});

return Task.CompletedTask;
}

private static Row CreateRow(object?[] rowItems) =>
Expand Down
3 changes: 2 additions & 1 deletion applications/lokqlDx/Views/ChartView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public byte[] RenderToImage(KustoQueryResult result, double pWidth, double pHeig

public void RenderToDisplay(KustoQueryResult result, KustoSettingsProvider kustoSettings) =>
//important - this can be called from inside the engine so we need to dispatch it to the UI thread
DispatcherHelper.SafeInvoke(() =>
//use Post instead of Invoke to avoid deadlock if already on UI thread
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
{
PlotControl.Reset();
var plot = PlotControl.Plot;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using AvaloniaEdit;

namespace LokqlDx.Views.Dialogs;

Expand All @@ -12,9 +13,17 @@ public ApplicationPreferencesView()
}

private void OnThemeChanged()
=> HighlightHelper.ApplySyntaxHighlighting(TextEditor);
{
var textEditor = this.FindControl<TextEditor>("TextEditor");
if (textEditor != null)
HighlightHelper.ApplySyntaxHighlighting(textEditor);
}


private void UserControl_Loaded(object? sender, RoutedEventArgs e) =>
HighlightHelper.ApplySyntaxHighlighting(TextEditor);
private void UserControl_Loaded(object? sender, RoutedEventArgs e)
{
var textEditor = this.FindControl<TextEditor>("TextEditor");
if (textEditor != null)
HighlightHelper.ApplySyntaxHighlighting(textEditor);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using AvaloniaEdit;

namespace LokqlDx.Views.Dialogs;

Expand All @@ -10,6 +11,10 @@ public WorkspacePreferencesView()
InitializeComponent();
}

private void UserControl_Loaded(object? sender, RoutedEventArgs e) =>
HighlightHelper.ApplySyntaxHighlighting(TextEditor);
private void UserControl_Loaded(object? sender, RoutedEventArgs e)
{
var textEditor = this.FindControl<TextEditor>("TextEditor");
if (textEditor != null)
HighlightHelper.ApplySyntaxHighlighting(textEditor);
}
}
19 changes: 17 additions & 2 deletions applications/lokqlDx/Views/DispatcherHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ namespace LokqlDx.Views;
public static class DispatcherHelper
{
public static async Task<T> SafeInvoke<T>(Func<Task<T>> func) => await Dispatcher.UIThread.InvokeAsync(func);
public static T SafeInvoke<T>(Func<T> func) => Dispatcher.UIThread.Invoke(func);
public static void SafeInvoke(Action func) => Dispatcher.UIThread.Invoke(func);

public static T SafeInvoke<T>(Func<T> func)
{
// If already on UI thread, execute directly to avoid deadlock
if (Dispatcher.UIThread.CheckAccess())
return func();
return Dispatcher.UIThread.Invoke(func);
}

public static void SafeInvoke(Action func)
{
// If already on UI thread, execute directly to avoid deadlock
if (Dispatcher.UIThread.CheckAccess())
func();
else
Dispatcher.UIThread.Invoke(func);
}
}
2 changes: 1 addition & 1 deletion applications/lokqlDx/Views/QueryContextView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs
IsExpanded: true
})
// Ensure focus is set on the UI thread
Dispatcher.UIThread.Post(() => ParametersTextBox.Focus());
Dispatcher.UIThread.Post(() => this.FindControl<TextBox>("ParametersTextBox")?.Focus());
}
}
52 changes: 33 additions & 19 deletions applications/lokqlDx/Views/QueryEditorView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using AvaloniaEdit;
using LokqlDx.ViewModels;
using lokqlDxComponents;
using lokqlDxComponents.Views.Dialogs;
Expand All @@ -12,34 +13,44 @@ namespace LokqlDx.Views;

public partial class QueryEditorView : UserControl
{
private readonly EditorHelper _editorHelper;
private EditorHelper? _editorHelper;
private CompletionManager? _completionManager;

private TextEditor? _textEditor;

public QueryEditorView()
{
InitializeComponent();
_editorHelper = new EditorHelper(TextEditor);
_textEditor = this.FindControl<TextEditor>("TextEditor");
if (_textEditor != null)
{
_editorHelper = new EditorHelper(_textEditor);
}
Messaging.RegisterForEvent<ThemeChangedMessage>(this, OnThemeChanged);
}

private void OnThemeChanged() => HighlightHelper.ApplySyntaxHighlighting(TextEditor);
private void OnThemeChanged()
{
if (_textEditor != null)
HighlightHelper.ApplySyntaxHighlighting(_textEditor);
}

private QueryEditorViewModel? GetVm() =>
(DataContext as QueryEditorViewModel)!;


private void UserControl_Loaded(object? sender, RoutedEventArgs e)
{
HighlightHelper.ApplySyntaxHighlighting(TextEditor);
if (_textEditor == null) return;

HighlightHelper.ApplySyntaxHighlighting(_textEditor);
//Ensure we can intercept ENTER key
TextEditor.AddHandler(KeyDownEvent, InternalEditor_OnKeyDown, RoutingStrategies.Tunnel);
TextEditor.AddHandler(DragDrop.DragEnterEvent, DragEnter);
TextEditor.AddHandler(DragDrop.DragOverEvent, DragOver);
TextEditor.AddHandler(DragDrop.DropEvent, Drop);
TextEditor.TextArea.TextEntered += TextArea_TextEntered;
TextEditor.TextArea.TextView.LinkTextUnderline = true;
TextEditor.TextArea.TextView.LinkTextForegroundBrush = Brushes.LightGreen;
_textEditor.AddHandler(KeyDownEvent, InternalEditor_OnKeyDown, RoutingStrategies.Tunnel);
_textEditor.AddHandler(DragDrop.DragEnterEvent, DragEnter);
_textEditor.AddHandler(DragDrop.DragOverEvent, DragOver);
_textEditor.AddHandler(DragDrop.DropEvent, Drop);
_textEditor.TextArea.TextEntered += TextArea_TextEntered;
_textEditor.TextArea.TextView.LinkTextUnderline = true;
_textEditor.TextArea.TextView.LinkTextForegroundBrush = Brushes.LightGreen;
}

private async void TextArea_TextEntered(object? sender, TextInputEventArgs e)
Expand All @@ -54,12 +65,15 @@ private void DragEnter(object? sender, DragEventArgs drgevent)
=> DragDropManager.DragEnter(drgevent);

private void Drop(object? sender, DragEventArgs e)
=> DragDropManager.Drop(e, _editorHelper);
{
if (_editorHelper != null)
DragDropManager.Drop(e, _editorHelper);
}


private async void InternalEditor_OnKeyDown(object? sender, KeyEventArgs e)
{
if (GetVm() is not { } vm)
if (GetVm() is not { } vm || _editorHelper == null)
return;
await QueryExecutionHelper.HandleKeyCombo(e, _editorHelper, vm);
vm.EditorOffset = _editorHelper.CurrentOffset();
Expand All @@ -68,12 +82,12 @@ private async void InternalEditor_OnKeyDown(object? sender, KeyEventArgs e)

private void TextEditor_OnLoaded(object? sender, RoutedEventArgs e)
{
if (GetVm() is not { } vm)
if (GetVm() is not { } vm || _textEditor == null || _editorHelper == null)
return;
_completionManager = new CompletionManager(TextEditor, _editorHelper, vm,
new CompletionWindowWrapper(TextEditor.TextArea));
TextEditor.TextArea.Focus();
_completionManager = new CompletionManager(_textEditor, _editorHelper, vm,
new CompletionWindowWrapper(_textEditor.TextArea));
_textEditor.TextArea.Focus();
}

private void InputElement_OnGotFocus(object? sender, GotFocusEventArgs e) => TextEditor.Focus();
private void InputElement_OnGotFocus(object? sender, GotFocusEventArgs e) => _textEditor?.Focus();
}
10 changes: 8 additions & 2 deletions applications/lokqlDx/Views/RenderingSurfaceView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace LokqlDx.Views;

public partial class RenderingSurfaceView : UserControl, IDisposable
{
private TreeDataGrid? _dataGrid;

public RenderingSurfaceView()
{
InitializeComponent();
Expand All @@ -21,12 +23,16 @@ public void Dispose()
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
DataGrid.KeyDown += DataGrid_KeyDown;
_dataGrid = this.FindControl<TreeDataGrid>("DataGrid");
if (_dataGrid != null)
{
_dataGrid.KeyDown += DataGrid_KeyDown;
}
}

private async void DataGrid_KeyDown(object? sender, KeyEventArgs e)
{
var vm = DataGrid.DataContext as RenderingSurfaceViewModel;
var vm = _dataGrid?.DataContext as RenderingSurfaceViewModel;
if (vm != null)
if ((e.KeyModifiers & KeyModifiers.Control) != 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ private IImage LoadImage(string path)
{
var stream = assetService.Open(path);
logger.LogTrace("Loaded asset");
var res = Dispatcher.UIThread.Invoke(() => CreateImage(path, stream));
// Check if already on UI thread to avoid deadlock
IImage res;
if (Dispatcher.UIThread.CheckAccess())
res = CreateImage(path, stream);
else
res = Dispatcher.UIThread.Invoke(() => CreateImage(path, stream));
logger.LogTrace("Created image");
_imageCache[path] = res;
return res;
Expand All @@ -105,4 +110,4 @@ private IImage LoadImage(string path)
return NullImage.Instance;
}
}
}
}
Loading