uno.extensions icon indicating copy to clipboard operation
uno.extensions copied to clipboard

docs: Add ViewMap and DataContext troubleshooting guide with navigation lifecycle deep dive

Open Copilot opened this issue 4 months ago • 5 comments

PR Type

  • Documentation content changes

What is the current behavior?

Developers debugging null DataContext issues lack documentation on:

  • ViewMap's internal type registration and view-viewmodel association mechanism
  • DataContext assignment timing and lifecycle during navigation
  • Complete navigation lifecycle flow from request to DataContext assignment
  • Systematic troubleshooting steps
  • DI container and ViewMap registration prerequisites

What is the new behavior?

New troubleshooting guide (Troubleshooting-ViewMap-DataContext.md) documents:

Internal Mechanisms

  • ViewMap type registration flow: ViewMap → DI container → view-viewmodel mapping
  • DataContext assignment sequence: navigation request → route resolution → view creation → viewmodel resolution → DataContext assignment
  • Actual framework code showing view.DataContext = viewModel in FrameworkElementExtensions.cs

Navigation Lifecycle Deep Dive

  • Mermaid sequence diagram visualizing complete navigation flow with 9 participants (Application, INavigator, RouteUpdater, RouteResolver, Region, ControlNavigator, DI Container, View, ViewModel)
  • 8 key stages explained in detail: Navigation Initiation, Route Initialization/Redirection, Route Resolution, Region-Specific Navigation, View Creation, ViewModel Creation, DataContext Assignment, and View Display
  • ViewModel creation process showing DI resolution order and constructor patterns
  • Verification points table mapping each lifecycle stage to diagnostic checks
  • Common lifecycle failure points with symptoms, causes, and fixes

Diagnostic Process

Six-step troubleshooting workflow:

  1. Visual DataContext inspection via TextBlock binding
  2. ViewMap registration verification
  3. ViewModel constructor dependency validation
  4. Navigation call pattern review
  5. Region attachment inspection
  6. Diagnostic logging enablement

Common Issues

  • Null DataContext: missing ViewMap registration or DI dependencies
  • Binding failures: missing INotifyPropertyChanged implementation
  • Wrong DataContext type: conflicting ViewMap registrations
  • Manual DataContext conflicts: code-behind assignments interfering with framework

Developer Tools

  • Breakpoint locations in framework code
  • Custom NavigationRequestHandler for logging
  • View Loaded event inspection
  • Visual tree DataContext traversal helper

Documentation Cross-References

  • Added troubleshooting guide references in HowTo-DefineRoutes.md and NavigationOverview.md
  • Integrated standard getting-help include for support resources

PR Checklist

  • [ ] Tested code with current supported SDKs
  • [x] Docs have been added/updated which fit documentation template. (for bug fixes / features)
  • [ ] Unit Tests and/or UI Tests for the changes have been added (for bug fixes / features) (if applicable)
  • [ ] Wasm UI Tests are not showing unexpected any differences. Validate PR Screenshots Compare Test Run results.
  • [x] Contains NO breaking changes
  • [ ] Updated the Release Notes
  • [x] Associated with an issue (GitHub or internal)

Other information

Documentation follows conventional commits format. Changes based on code review feedback:

  • Replaced unicode arrows with NOTE: comments for broader renderer compatibility
  • Clarified Frame navigation references
  • Removed confusing design-time DataContext section
  • Added comprehensive navigation lifecycle visualization and explanation with mermaid diagram
  • Replaced custom Additional Resources section with standard getting-help include
  • Validated all lifecycle stages against codebase (Navigator.cs, ControlNavigator.cs, FrameNavigator.cs, FrameworkElementExtensions.cs)
  • Fixed Frame.Navigate syntax to use typeof(MainPage) instead of page instance
  • Fixed markdown linting issues: added blank lines around lists and code blocks, added language specifiers to code blocks
Original prompt

This section details on the original issue you should resolve

<issue_title>[Documentation] [Navigation] ViewMap/DataContext Troubleshooting and Internal Mechanism Documentation</issue_title> <issue_description>## Problem Statement

I recently spent significant time debugging what seemed like a simple issue: a button in my XAML wasn't responding to clicks. The bindings appeared correct, the UI rendered fine, but nothing worked. The root cause was that DataContext was null, and the current documentation doesn't adequately explain:

  1. How ViewMap actually works internally
  2. When and how DataContext gets assigned
  3. How to troubleshoot when it doesn't work
  4. What the prerequisites are (DI + ViewMap relationship)

The current documentation leaves developers without clear guidance on these critical aspects of the navigation system.


My Debugging Journey

Here's what I had to figure out to solve this issue:

Attempt 1: Visual Debugging

Added a debug TextBlock to display the DataContext type:

<TextBlock x:Name="DebugText" Foreground="Red" FontSize="20"/>
this.Loaded += (s, e) => {
    DebugText.Text = $"DataContext: {DataContext?.GetType().Name ?? "NULL"}";
};

Result: Confirmed DataContext was NULL. But why?

Attempt 2: Constructor Logging

public MyPage()
{
    Debug.WriteLine("[MyPage] Constructor called");
    InitializeComponent();
    Debug.WriteLine($"[MyPage] DataContext: {DataContext?.GetType().Name ?? "NULL"}");
}

Problem discovered: Debug.WriteLine() doesn't appear in PowerShell background jobs. Had to switch to Console.WriteLine().

Result: Page constructor runs, but DataContext is NULL after InitializeComponent().

Attempt 3: ViewModel Constructor Logging

public class MyViewModel : ObservableObject
{
    public MyViewModel(INavigator navigator)
    {
        Console.WriteLine("[MyViewModel] Constructor called");
    }
}

Result: No log output on first launch. ViewModel was never created!

Attempt 4: Verify DI Registration

Checked App.xaml.cs:

services.AddTransient<MyViewModel>(); // ✓ Present
.UseNavigation(new ViewMap<MyPage, MyViewModel>()) // ✓ Present

Everything looked correct, but still didn't work.

Attempt 5: Hot Reload Test

Made a minor XAML change and saved the file.

BREAKTHROUGH: After Hot Reload:

[MyViewModel] Constructor called
[MyPage] Loaded - DataContext: MyViewModel

Conclusion: ViewMap WORKS, but only after Hot Reload. There's an initialization timing issue on first app launch.


What's Missing from the Documentation

The current View and ViewModel page doesn't adequately cover:

1. How ViewMap Actually Works (Critical Gap)

Current state: Documentation says ViewMap "associates" a View with a ViewModel, but doesn't explain the mechanism.

What's needed: A clear explanation like:

When you register new ViewMap<MyPage, MyViewModel>() and navigate to MyViewModel, the framework:

  1. Resolves MyViewModel from the DI container
  2. Creates a new instance of MyPage
  3. Automatically sets myPageInstance.DataContext = myViewModelInstance

Important: You do NOT need to manually set DataContext in your page's code-behind. ViewMap handles this automatically.

Why it matters: Without this clarity, developers may assume they need to manually wire up DataContext, leading to incorrect implementations and confusion.


2. Troubleshooting Section (Critical Gap)

Current state: No troubleshooting guidance exists.

What's needed: A dedicated troubleshooting page covering:

Problem: DataContext is null, bindings don't work

Diagnostic Steps:

  1. Verify DataContext in Page.Loaded:

    this.Loaded += (s, e) => {
        Console.WriteLine($"DataContext: {DataContext?.GetType().Name ?? "NULL"}");
    };
    
  2. Check BOTH registrations are present:

    // Both required:
    services.AddTransient<MyViewModel>();  // DI registration
    .UseNavigation(new ViewMap<MyPage, MyViewModel>())  // ViewMap registration
    
  3. Verify ViewModel constructor is called:

    public MyViewModel(INavigator navigator) {
        Console.WriteLine($"[MyViewModel] Created");
    }
    

    If this log doesn't appear → DI registration issue or missing dependency.

  4. Test with Hot Reload:

    • Make a small XAML change
    • If DataContext works after Hot Reload but not on first launch → Initialization timing issue

Why it matters: Without this guidance, developers are left without a clear path to diagnose and resolve issues.


3. DI + ViewMap Prerequisites (Critical Gap)...

  • Fixes unoplatform/uno.extensions#2983

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot avatar Dec 18 '25 18:12 Copilot