dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.06k stars 1.17k forks source link

Problem with loading component in WPF project #1688

Open grubioe opened 5 years ago

grubioe commented 5 years ago

@ds1709 commented on Wed Aug 14 2019

Issue Title

Problem with loading component in WPF project by calling Application.LoadComponent(Uri).

General

Version: .NET Core 3.0.0 Preview 8. OS: Windows 10. Visual Studio: 2019 16.2.1. Project Sdk: Microsoft.NET.Sdk.WindowsDesktop.

In the next scenario Application.LoadComponent(Uri) throws exception. Created a simple WPF application with classe App and MainWindow.

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <UseWPF>true</UseWPF>
    <AssemblyVersion>1.2.3.54</AssemblyVersion>
  </PropertyGroup>
</Project>
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Border x:Name="Foo" />
    </Grid>
</Window>
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        var uri = new Uri("/WpfApp1;component/mainwindow.xaml", UriKind.Relative);
        var window = LoadComponent(uri); // Exception: Cannot register duplicate Name 'Foo' in this scope.
    }
}

Key points here are <AssemblyVersion> in csproj file and named element in MainWindow xaml file. When it's declared, the window code generator creates code like System.Uri resourceLocater = new System.Uri("/WpfApp1;V1.2.3.54;component/mainwindow.xaml", System.UriKind.Relative);. As you can see, there's version element in URI. But when <AssemblyVersion> is not declared, or version is declared in code ([assembly:AssemblyVersion("...")]), then version is missing in generated URI, and exception is not throwing. Same for UserControls.


@carlossanlop commented on Wed Aug 14 2019

// Exception: Cannot register duplicate Name 'Foo' in this scope.

@ds1709 thank you for the details.

@grubioe can you help with this issue? Feel free to transfer it to the dotnet/wpf repo if necessary.


@grubioe commented on Wed Aug 14 2019

@diverdan92 - this might be more related with VS, maybe in the project system, the code generator. Can you route to the right team?

grubioe commented 5 years ago

From an internal discussion:

It looks like the version is included in the URL here: https://github.com/dotnet/wpf/blame/master/src/Microsoft.DotNet.Wpf/src/PresentationBuildTasks/MS/Internal/MarkupCompiler/MarkupCompiler.cs#L2599-L2601

ryalanms commented 5 years ago

Yes, this looks like an existing WPF issue in .NET Framework also present in .NET Core. ‘Version’ should not be required in the URI unless there are two versions of the assembly loaded. The work-around is to include the version in the URI when calling LoadComponent:

/MyApp;V3.2.1;component/mainwindow.xaml

HClausing commented 4 years ago

This started to happen to me after upgrading Visual Studio 16.7.2 to 16.7.6.

Code:

    public static async void LoadApplication(Application.ApplicationInstance item)
    {
        if (item.IsLoading == false || item.Content != null) return;
        try
        {
            UIElement app = System.Windows.Application.LoadComponent(new Uri(item.StartupURI, UriKind.RelativeOrAbsolute)) as UIElement;
            if (app != null) item.Content = app;
            item.IsLoading = false;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

The error occurs here, if the component had at least one element with x:Name: UIElement app = System.Windows.Application.LoadComponent(new Uri(item.StartupURI, UriKind.RelativeOrAbsolute)) as UIElement;

Before the update my app was running as expected.

I've tried to put version on URI, but the error persists: StartupURI="/LabsApp.WPF;1.0.2.0;component/View/Order2.xaml"

If I put the Orders2.Xaml as a child of MainWindow statically, it works.

Trace:

---> System.ArgumentException: Não é possível registrar Nome duplicado 'pages' neste escopo. at System.Xaml.NameScope.RegisterName(String name, Object scopedElement) at System.Xaml.XamlObjectWriter.RegisterName(ObjectWriterContext ctx, String name, Object inst, XamlType xamlType, INameScope nameScope, INameScope parentNameScope, Boolean isRoot) --- End of inner exception stack trace --- at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri) at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri) at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri) at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream) at System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc) at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties) at System.Windows.Application.LoadComponent(Uri resourceLocator) at EficazFrameworkCore.Controls.MDIContainer.LoadApplication(ApplicationInstance item)

HClausing commented 4 years ago

I've found what is causing this problem. It happens when AssemblyVersion tag is present on csproj file:

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
    <SignAssembly>true</SignAssembly>
    <DelaySign>false</DelaySign>
    <AssemblyOriginatorKeyFile>EficazContent.pfx</AssemblyOriginatorKeyFile>
    <Description>adsasd</Description>
    <AssemblyVersion>1.0.5.0</AssemblyVersion>   <----HERE
    <PackageReleaseNotes>dfsdf</PackageReleaseNotes>
  </PropertyGroup>

If I remove this tag, the Application.LoadComponent() works as expected:

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
    <SignAssembly>true</SignAssembly>
    <DelaySign>false</DelaySign>
    <AssemblyOriginatorKeyFile>EficazContent.pfx</AssemblyOriginatorKeyFile>
    <Description>adsasd</Description>
    <PackageReleaseNotes>dfsdf</PackageReleaseNotes>
  </PropertyGroup>

FileVersion tag algo cause the problem.

vatsan-madhavan commented 4 years ago

@HClausing #2517 and #2691 might be of interest to you.