Table of Contents

Class DesignSession

Namespace
Icy.Design
Assembly
IcyUI.Design.dll

Tracks every markup page a configuration loads, so the pages can be edited live and saved back as markup.

public sealed class DesignSession : IDisposable
Inheritance
DesignSession
Implements
Inherited Members
Extension Methods

Remarks

Attach a session before loading the pages you want to edit; pages loaded earlier aren't tracked. Release builds of a game shouldn't attach one at all, and needn't reference this assembly:

#if DEBUG
using DesignSession session = DesignSession.Attach(configuration);
#endif

The session never keeps a page alive. When a page is collected, its document is dropped the next time the session is asked for documents.

Properties

Configuration

Gets the configuration this session tracks loads for.

public IcyConfiguration Configuration { get; }

Property Value

IcyConfiguration

Documents

Gets the documents of every tracked page still alive.

public IReadOnlyList<DesignDocument> Documents { get; }

Property Value

IReadOnlyList<DesignDocument>

SourcePathResolver

Gets or sets how Save() turns a document's SourcePath into a file to write.

public Func<string, string?> SourcePathResolver { get; set; }

Property Value

Func<string, string>

Remarks

A source path is whatever the page was loaded with, often an asset name such as Pages/Main.xml resolved through an IAssetContext. By default an existing file path resolves to its full path and anything else to null, which makes Save() throw. Set this to map asset names to source files in your project.

Exceptions

ArgumentNullException

The value is null.

Methods

Attach(IcyConfiguration)

Starts tracking every page configuration loads from now on.

public static DesignSession Attach(IcyConfiguration configuration)

Parameters

configuration IcyConfiguration

The configuration whose loads to track.

Returns

DesignSession

The new session. Dispose it to stop tracking.

Exceptions

ArgumentNullException

configuration is null.

InvalidOperationException

configuration already has a LoadObserver, such as another session's.

Dispose()

Stops tracking loads, and detaches every document. Their editors throw ObjectDisposedException from then on.

public void Dispose()

FindDocument(object, out NodeId)

Finds the document a live object was built from, and the markup element it was built from.

public DesignDocument? FindDocument(object instance, out NodeId node)

Parameters

instance object

A live object, typically a UIElement of a tracked page.

node NodeId

The markup element instance was built from.

Returns

DesignDocument

The document, or null when instance doesn't come from a tracked page: it was added by code at runtime, or its page was loaded before the session was attached.

Exceptions

ArgumentNullException

instance is null.

FindSourceRoot(string, string)

Finds a source folder by walking up from BaseDirectory to the first directory that contains marker.

public static string? FindSourceRoot(string marker, string relative = "")

Parameters

marker string

A file name that marks the project folder, such as MyGame.csproj.

relative string

The path from that folder to the markup files, such as Assets/UI.

Returns

string

The combined path, or null when no ancestor contains the marker.

Examples

if (DesignSession.FindSourceRoot("MyGame.csproj", "Assets/UI") is { } root)
    session.UseSourceRoot(root);

FindSourceRoot(string, string, string)

Finds a source folder by walking up from startDirectory to the first directory that contains marker.

public static string? FindSourceRoot(string startDirectory, string marker, string relative)

Parameters

startDirectory string

The directory to start from.

marker string

A file name that marks the project folder.

relative string

The path from that folder to the markup files.

Returns

string

The combined path, or null when no ancestor contains the marker.

SaveAll()

Saves every modified document that can be saved.

public IReadOnlyList<(DesignDocument Document, string Reason)> SaveAll()

Returns

IReadOnlyList<(DesignDocument Document, string Reason)>

The modified documents that weren't saved, with the reason: SaveBlockedReason, or the message of the error that stopped the write. Never throws for one document's failure.

Exceptions

ObjectDisposedException

The session was disposed.

UseSourceRoot(string)

Makes Save() write each page to root combined with its source path, for pages loaded by asset name such as UI/MainMenu.xml.

public void UseSourceRoot(string root)

Parameters

root string

The folder holding the source markup files, usually inside the game project.

Remarks

Only existing files resolve, so a typo in the root disables Save with a reason instead of creating files in the wrong place. Use FindSourceRoot(string, string) to locate the folder from the running game.

Exceptions

ArgumentException

root is null or empty.

WatchSourceFiles()

Reloads a tracked page when its source file changes on disk, so edits saved in a text editor show in the running game.

public IDisposable WatchSourceFiles()

Returns

IDisposable

A handle that stops watching when disposed.

Remarks

  • It watches the folders of the source files SourcePathResolver resolves (see UseSourceRoot(string)), for the documents tracked now and those tracked later.
  • A change is debounced (editors write in several steps) and applied on the thread that called this method, which must be the UI thread: the next Canvas.Render runs it, through that thread's Dispatcher.
  • A file whose text already equals its document's isn't reloaded, so a save from the in-game editor doesn't reload itself. A file that can't be read is retried once, then skipped until its next change.
  • Only *.xml files of tracked pages are watched, not merged resource dictionaries.

Opt-in and for development: nothing is watched unless you call this, so call it only in Debug builds.

Exceptions

ObjectDisposedException

The session was disposed.