Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Extensions for UIElements
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using UnityEngine.UIElements;
// ReSharper disable once CheckNamespace
namespace UnityEditor
{
[PublicAPI]
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "StringLiteralTypo")]
[SuppressMessage("ReSharper", "CommentTypo")]
public static class EditorWindowExtensions
{
/// <summary>
/// Loads the visual tree.
/// <para>
/// This method loads the visual tree and associated style sheet using default Unity conventions,
/// that is, UXML and USS files are expected to be located next to this instance script asset.
/// </para>
/// <para>
/// Declared instance fields that derive from <see cref="VisualElement" /> will be assigned
/// the matching element instance found when searching the visual tree.
/// </para>
/// </summary>
/// <param name="window">
/// Source window.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="window" /> is <c>null</c>.
/// </exception>
/// <exception cref="FileNotFoundException">
/// Associated UMXL or USS file could not be found.
/// </exception>
/// <exception cref="InvalidOperationException">
/// A declared instance field deriving from <see cref="VisualElement" /> could not be found in the visual tree.
/// </exception>
public static void LoadVisualTree([NotNull] this EditorWindow window)
{
if (window == null)
throw new ArgumentNullException(nameof(window));
var script = MonoScript.FromScriptableObject(window);
var path = AssetDatabase.GetAssetPath(script);
var xml = Path.ChangeExtension(path, "uxml");
var css = Path.ChangeExtension(path, "uss");
var asset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(xml);
if (asset == null)
throw new FileNotFoundException("Associated UXML file could not be found.");
var sheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(css);
if (sheet == null)
throw new FileNotFoundException("Associated USS file could not be found.");
var tree = asset.CloneTree();
tree.styleSheets.Add(sheet);
window.rootVisualElement.Clear();
window.rootVisualElement.Add(tree);
var fields = window
.GetType()
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)
.Where(s => typeof(VisualElement).IsAssignableFrom(s.FieldType))
.ToArray();
foreach (var field in fields)
{
var name = field.Name;
var type = field.FieldType;
var element = tree.Q(name);
if (element == null)
throw new InvalidOperationException($"Element '{name}' of type '{type}' could not be found in visual tree.");
field.SetValue(window, element);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.