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
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@
<Design.DataContext>
<vm:MainWindowViewModel />
</Design.DataContext>
<Grid RowDefinitions="Auto,Auto,*">
<Button Content="Execute Script" Grid.Row="0" Margin="5">
<StackPanel Spacing="5">
<TextBox Name="ScriptTextBox" Text="Console.WriteLine((Sender as Control).Bounds);" />
<Button Content="Execute Script" >
<Interaction.Behaviors>
<EventTriggerBehavior EventName="Click" >
<ExecuteScriptAction Script="{Binding #ScriptTextBox.Text}" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Button>
<Button Content="Execute Script - System.Console.WriteLine" >
<Interaction.Behaviors>
<EventTriggerBehavior EventName="Click" >
<ExecuteScriptAction Script="System.Console.WriteLine(&quot;Hi from script.&quot;);" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Button>
<Button Content="Execute Script - Access Globals" Grid.Row="1" Margin="5">
<Button Content="Execute Script - Access Globals">
<Interaction.Behaviors>
<EventTriggerBehavior EventName="Click" >
<ExecuteScriptAction Script="System.Console.WriteLine(Sender);" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Button>
</Grid>
</StackPanel>
</UserControl>
71 changes: 63 additions & 8 deletions src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Avalonia.Threading;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Avalonia.Xaml.Interactivity;
using Microsoft.CodeAnalysis.Scripting;

namespace Avalonia.Xaml.Interactions.Scripting;

Expand All @@ -13,6 +17,21 @@
[RequiresUnreferencedCode("This functionality is not compatible with trimming.")]
public class ExecuteScriptAction : StyledElementAction
{
private static string[] s_imports = [
"System",
"System.Collections.Generic",
"System.Linq",
"Avalonia",
"Avalonia.Collections",
"Avalonia.Controls",
"Avalonia.Interactivity",
"Avalonia.Metadata",
"Avalonia.LogicalTree",
"Avalonia.Reactive",
"Avalonia.Input",
"Avalonia.Markup.Xaml"
];

/// <summary>
/// Identifies the <see cref="Script"/> avalonia property.
/// </summary>
Expand All @@ -28,27 +47,63 @@
set => SetValue(ScriptProperty, value);
}

/// <summary>
/// Run script using Dispatcher.UIThread.InvokeAsync instead Task.Run.
/// </summary>
public bool UseDispatcher { get; set; } = true;

/// <inheritdoc />
public override object Execute(object? sender, object? parameter)
{
if (!IsEnabled)
{
return false;
}

if (string.IsNullOrWhiteSpace(Script))
{
return false;
}

var script = Script;
var globals = new ExecuteScriptActionGlobals(sender, parameter);
var loadedAssemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic && !string.IsNullOrEmpty(a.Location))

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build ubuntu-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build ubuntu-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build macos-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build macos-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build windows-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.

Check warning on line 72 in src/Avalonia.Xaml.Interactions.Scripting/ExecuteScriptAction.cs

View workflow job for this annotation

GitHub Actions / Build windows-latest

'System.Reflection.Assembly.Location' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
.ToArray();

_ = Dispatcher.UIThread.InvokeAsync(async () =>
if (UseDispatcher)
{
try
_ = Dispatcher.UIThread.InvokeAsync(async () =>
{
_ = await CSharpScript.EvaluateAsync(Script, globals: globals);
}
catch (Exception ex)
await Run(loadedAssemblies, script, s_imports, globals);
});
}
else
{
_ = Task.Run(async () =>
{
Debug.WriteLine($"Script execution failed: {ex.Message}");
}
});
await Run(loadedAssemblies, script, s_imports, globals);
});
}

return true;
}

private static async Task Run(
Assembly[] loadedAssemblies,
string? script,
string[] imports,
ExecuteScriptActionGlobals globals)
{
try
{
var options = ScriptOptions.Default.WithImports(imports).WithReferences(loadedAssemblies);
_ = await CSharpScript.RunAsync(script, options, globals);
}
catch (Exception ex)
{
Debug.WriteLine($"Script execution failed: {ex.Message}");
}
}
}
Loading