lepoco / wpfui

WPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly.
https://wpfui.lepo.co
MIT License
7.73k stars 756 forks source link

Powershell WPF: unable to use "TargetPageType" in NavigationViewItem and cannot display a page. #1219

Open Ka1Nn opened 2 months ago

Ka1Nn commented 2 months ago

Describe the bug

I'm trying to use the standard approach in PowerShell WPF for setting up a NavigationViewItem in a FluentWindow. However, it's not working as expected, and the NavigationViewItem appears empty.

Here’s the code I’m using:

To Reproduce

Powershell.ps1

$ScriptPath = if ($psISE) {
    Split-Path $psise.CurrentFile.FullPath
} else {
    if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript") { 
        Split-Path -Parent -Path $MyInvocation.MyCommand.Definition 
    } else { 
        Split-Path -Parent -Path ([Environment]::GetCommandLineArgs()[0]) 
    }
}

# Loading necessary assemblies
$allAssemblies = @(
    'presentationframework', 
    'WindowsBase', 
    'PresentationCore',
    "$ScriptPath\packages\wpf-ui\3.0.5\lib\net481\wpf.ui.dll"
)

foreach ($assembly in $allAssemblies) {
    if ($assembly -like "*.dll") {
        if (Test-Path $assembly) {
            Add-Type -Path $assembly
        } else {
            Write-Error "Cannot locate assembly at $assembly"
        }
    } else {
        Add-Type -AssemblyName $assembly
    }
}

# Loading the main window XAML
$XAML = @"
<ui:FluentWindow xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                 xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                 xmlns:ui='http://schemas.lepo.co/wpfui/2022/xaml'
                 Title='MainWindow' Height='450' Width='800'>
    <ui:FluentWindow.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ui:ThemesDictionary Theme='Light' />
                <ui:ControlsDictionary />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </ui:FluentWindow.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height='Auto' />
            <RowDefinition Height='*' />
        </Grid.RowDefinitions>

        <ui:TitleBar x:Name='TitleBar'
                     Title='Pane Title'
                     Grid.Row='0'
                     CloseWindowByDoubleClickOnIcon='True'>
            <ui:TitleBar.Icon>
                <ui:ImageIcon Source='$ScriptPath/Assets/wpfui-icon-256.png' />
            </ui:TitleBar.Icon>
        </ui:TitleBar>

        <ui:NavigationView x:Name='RootNavigation'
                           Grid.Row='1'
                           MinHeight='300'
                           Margin='0'
                           IsBackButtonVisible='Auto'
                           IsPaneToggleVisible='True'
                           PaneDisplayMode='Left'
                           PaneTitle='Pane Title'>
            <ui:NavigationView.MenuItems>
                <ui:NavigationViewItem x:Name='HomeMenu'
                                       Content='Home'
                                       Icon='{ui:SymbolIcon Home24}' />
            </ui:NavigationView.MenuItems>
        </ui:NavigationView>
    </Grid>
</ui:FluentWindow>
"@

$reader = (New-Object System.Xml.XmlNodeReader ([xml]$XAML))
$Window = [System.Windows.Markup.XamlReader]::Load($reader)

# Load the UserControl XAML
function LoadXaml ($filename){
    $XamlLoader=(New-Object System.Xml.XmlDocument)
    $XamlLoader.Load($filename)
    return $XamlLoader
}

$XamlMainWindow = LoadXaml("$ScriptPath\HomePage.xaml")
$Reader = New-Object System.Xml.XmlNodeReader $XamlMainWindow
$homePageContent = [Windows.Markup.XamlReader]::Load($Reader)

# Extract necessary controls
$RootNavigation = $Window.FindName('RootNavigation')
$HomeMenu = $Window.FindName('HomeMenu')

# Attempt to set the TargetPageType directly
$HomeMenu.TargetPageType = $homePageContent.GetType()

# Show the window
$Window.ShowDialog()

Home.xaml looks like

<Page
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
        </Grid.RowDefinitions>

        <ui:Button Content="Click me!"
                   Icon="Fluent24" />
        <TextBlock Grid.Row="1"
                   Margin="12,0,0,0"
                   VerticalAlignment="Center"/>

    </Grid>
</Page>

Expected behavior

The XAML page content should be displayed correctly in the user interface when the corresponding menu item is selected, without requiring a compiled class.

Like i use powershell i'm not able to use TargetPageType Property to fill up the menu content.

the application opens but immediately freezes, making it unusable

Screenshots

image

OS version

Windows 11 22h2

.NET version

[System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription returns : .NET Framework 4.8.9261.0

WPF-UI NuGet version

wpf-ui\3.0.5\lib\net481\wpf.ui.dll

Additional context

No response

Ka1Nn commented 2 months ago

Here an update, that how i make it works

You need to declare classes :

class HomePage : System.Windows.Controls.UserControl {
    HomePage() {
        $this.LoadXamlFromFile()
    }

    [void] LoadXamlFromFile() {
        $xamlPath = "$global:ScriptPath\Views\Pages\Home.xaml" 
        $xmlDocument = New-Object System.Xml.XmlDocument
        $xmlDocument.Load($xamlPath)
        $reader = New-Object System.Xml.XmlNodeReader $xmlDocument
        $loadedContent = [System.Windows.Markup.XamlReader]::Load($reader)

        $this.Content = $loadedContent
    }
}

# Class ItemPage using a Grid instead of a Page
class ItemPage : System.Windows.Controls.Page {
    ItemPage() {
        $this.LoadXaml()
    }

    [void] LoadXaml() {
        $xaml = @"
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
      xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
      Width="800" Height="600"
      Background='LightBlue'>
    <TextBlock Text='Welcome to the Home Page!'
               VerticalAlignment='Center'
               HorizontalAlignment='Center'
               FontSize='24'/>
</Grid>
"@
        $stringReader = New-Object System.IO.StringReader($xaml)
        $xmlReader = [System.Xml.XmlReader]::Create($stringReader)
        $loadedContent = [System.Windows.Markup.XamlReader]::Load($xmlReader)

        $this.Content = $loadedContent
    }
}

Then initialize like this :

$HomeMenu.TargetPageType = [HomePage]::new().GetType()
$ItemsMenu.TargetPageType = [ItemPage]::new().GetType()

Note :

Please make something easier.. clearer... and usuable... I had never use classes to display a navigationViewItem before...