# MgGrid — Layout Persistence > Part of the MgGrid system. See `README.md` for overview and component hierarchy. ## Storage Keys Grid layouts are stored in **localStorage** with structured keys: ``` AutoSave: {AutoSaveLayoutName}_{MasterOrParentTypeName}_AutoSave_{UserId} UserSave: {AutoSaveLayoutName}_{MasterOrParentTypeName}_UserSave_{UserId} Splitter: Splitter_{grid.AutomaticLayoutStorageKey} ``` **Examples:** ``` GridOrder_Master_AutoSave_42 ← master grid, user #42 GridOrder_Order_AutoSave_42 ← detail grid under Order parent GridOrder_Master_UserSave_42 ← manually saved layout Splitter_GridOrder_Master_AutoSave_42 ← splitter pane size ``` ## Three Layout Tiers | Tier | Key Contains | When Saved | When Loaded | |---|---|---|---| | **Default** | (in-memory `_defaultLayoutJson`) | First `LayoutAutoLoading` — captures layout before any load | `ResetLayoutAsync()` — restores original | | **AutoSave** | `_AutoSave_` | Every `LayoutAutoSaving` event (on any layout change) | Every `LayoutAutoLoading` event (on grid init, wrapped in `BeginUpdate`/`EndUpdate`) | | **UserSave** | `_UserSave_` | `SaveUserLayoutAsync()` — explicit user action | `LoadUserLayoutAsync()` — explicit user action | ## Layout Operations | Method | Behavior | |---|---| | `SaveUserLayoutAsync()` | Saves to the local UserSave key first (the AutoSave key is already current — `LayoutAutoSaving` fires on every user-made layout change), then (when `EnableServerLayouts`) pushes the layout JSON to the server | | `LoadUserLayoutAsync()` | Prefers the server copy (when `EnableServerLayouts`) — writing it back to the local UserSave + AutoSave keys so it survives a page refresh — and falls back to the local UserSave copy; then applies the layout | | `ResetLayoutAsync()` | Removes AutoSave key, restores in-memory `_defaultLayoutJson` (never touches the server copy) | | `HasUserLayoutAsync()` | Local check; when `EnableServerLayouts` and no local copy exists, returns `true` optimistically — no server round-trip | ## Server Roaming (UserSave tier) `EnableServerLayouts` (default `true`) roams the **UserSave** tier through the grid's own `SignalRClient`, using the framework tags defined in `AcSignalRTags` (AyCode.Services): | Tag | Value | Params (in order) | Returns | |---|---|---|---| | `GetGridLayoutTag` | 90010 | `key` (string), `userId` (int) | layout JSON, or null | | `SaveGridLayoutTag` | 90011 | `key`, `layoutJson`, `userId` | bool | | `DeleteGridLayoutTag` | 90012 | `key`, `userId` | bool | - The `key` is the full composite UserSave storage key (it already contains the user id); the server treats it as an opaque string. `userId` comes from `GetLayoutUserId()`. - **Server communication happens exclusively on user clicks** (Save/Load layout toolbar buttons) — never on grid init, toolbar init, detail-row expand, or prerender. - All server calls are **best-effort** (`try/catch`): offline, or when the server does not implement the tags, behavior degrades to the local-only flow without errors. - The server must implement the three tags; the storage schema is the consumer's choice. - The `AutoSave` and `Splitter` tiers never touch the server. ## Persisted State The layout (`GridPersistentLayout`) includes: column order, column widths, sort descriptors, group descriptors, filter row values, page size — serialized as JSON via `System.Text.Json`. ## User Identification `GetLayoutUserId()` is virtual — defaults to `0`. Override in project adapter to provide the logged-in user's ID.