2009-09-21 9 views
18

O.k, to jest naprawdę irytujące, wcześniej zauważyłem, że kod generowany przez WPF do ładowania zasobów XAML nie wydaje się używać silnych nazw i dlatego może być problematyczny w scenariuszach, w których trzeba wspierać równoległe wersje złożeń WPF.Jak zmusić WPF do używania identyfikatorów URI zasobów, które używają silnej nazwy zespołu? Argh!

Okazało się, że tak jest, i teraz powoduje to problemy - mam system wtyczek, który ma obsługiwać instalację wtyczek różniących się tylko numerem wersji (wersją) . To oczywiście może być wspierane przez .NET, ponieważ assemblie są określane, aby mieć różne tożsamości, nawet jeśli mają tę samą nazwę pliku DLL, pod warunkiem, że są silnie nazwane i mają inny publiczny/prywatny klucz LUB mają inny numer wersji zespołu.

Teraz, jeśli spojrzymy na kod wygenerowany dla okien i usercontrols przez visual studio, widzimy w pliku generowanego automatycznie następuje:

/// <summary> 
/// InitializeComponent 
/// </summary> 
[System.Diagnostics.DebuggerNonUserCodeAttribute()] 
public void InitializeComponent() { 
    if (_contentLoaded) { 
     return; 
    } 
    _contentLoaded = true; 
    System.Uri resourceLocater = new System.Uri("/Sensormatic.AMK1000.Panel;component/views/servicepanelui.xaml", System.UriKind.Relative); 

    #line 1 "..\..\..\Views\ServicePanelUI.xaml" 
    System.Windows.Application.LoadComponent(this, resourceLocater); 

    #line default 
    #line hidden 
} 

Zawiadomienie linii, gdzie lokalizator zasobów jest tworzony - go używa względnego identyfikatora URI, który nie określa silnej nazwy lub wersji zestawu, który zawiera zasób xaml.

Pomyślałem, że może LoadComponent sprawdzi tożsamość zespołu wywołującego i użyje jego klucza publicznego i szczegółów wersji lub może sprawdzi tożsamość zespołu, który zawiera typ dla tego parametru.

Wygląda na to, że tak nie jest - jeśli masz dwa zespoły z różnymi numerami wersji (ale taką samą nazwę pliku), możesz uzyskać wyjątek IOException z komunikatem "Nie można zlokalizować zasobu X" (dla powyższego przykładu "Nie można zlokalizować zasobu "views/servicepanelui.xaml."

Co gorsza, jestem pewny, że oznacza to również, że złożenia o tej samej nazwie pliku, ale innym kluczu publicznym/prywatnym, tj. od różnych wydawców, również spowodują ten błąd

Więc, czy ktoś wie jak się z tym obejść? Jak sprawić, by nazwa WPF była zgodna z nazwą?

Uwaga, o ile mi wiadomo, jest to błąd WPF. Nie należy używać izolacji Appdomain, aby tego uniknąć.

+0

Cześć Phil, mam do czynienia z tym samym problemem. czy byłeś w stanie znaleźć jakieś rozwiązanie tego problemu? –

+0

Czy ktoś napotkał podobny problem z formantami niestandardowymi WPF używającymi motywów (za pomocą słowników zasobów)? Jeśli tak, jakieś rozwiązanie? – akjoshi

+0

jakieś wieści na ten temat? –

Odpowiedz

3

Zgadzam się, że jest to prawdopodobnie błąd, a przynajmniej niedobór oprzyrządowania XAML. Być może powinieneś zgłosić to na Connect.

nie próbowałem, ale oto kilka potencjalnych obejścia:

  1. wstrzyknąć etap pre-build do automatycznego modyfikowania plików .g.cs używać pack URIs określających pełną informację zmontują (AssemblyShortName [; Version] [; PublicKey]; komponent/Ścieżka)
  2. Dołączyć do AppDomain.AssemblyResolve pomóc CLR znaleźć odpowiedni montaż
+0

Dzięki Kent, chociaż miałem nadzieję, że będzie jakiś wbudowany sposób na obsługę tego! (chociaż tego nie znalazłem). Nie sądzę, że # 2 pomoże - całkiem pewny, że prośba o rozwiązanie zespołu będzie miała słabą nazwę, ponieważ właśnie to określa URI, a następnie nie wiem, który zestaw powinien być używany. # 1 może działać, chociaż oczywiście trochę brzydki. Przy okazji, świetna praca na kratownicy. Używam go w moim bieżącym projekcie. – Phil

+0

dołączanie do opcji assembly, brak wskazania, który z nich chcesz załadować, nie wydaje mi się użyteczne, może możesz użyć zespołu żądającego, jeśli jest on określony jako –

3

doznałem tego samego PROBL em i może to być możliwe rozwiązanie

za każdym razem, gdy kontrola jest tworzona za pomocą strony .xaml, na załączonym.konstruktor plik cs przed InitializeComponent() połączenia, należy dodać następujące wiersze:

 
contentLoaded = true; 
var assemblyName = GetType().Assembly.GetName(); 
System.Windows.Application.LoadComponent(GetType(), new Uri(
       string.Format("/{0};v{1};component{2}/{3}.xaml", 
       assemblyName.Name, 
       assemblyName.Version, 
       [[[namespace]]], 
       type.Name 
       ), UriKind.Relative)) 

gdzie jako [[[nazw]]] wprowadzić pełną nazw klasy, z wyjątkiem domyślnej przestrzeni nazw projektu Visual Studio

(Uwaga: istnieje Otwórz zaznaczone na connect https://connect.microsoft.com/VisualStudio/feedback/details/668914/xaml-generated-code-uses-resource-uri-without-assembly-strong-name)

+0

w [[[namespace]]] to nie jest przestrzeń nazw, ale położenie względem projektu strony, którą próbujesz wczytać (zwykle pokrywa się z obszarem nazw usuniętym z korzenia). –

5

można ustawić następujące w pliku projektu zmianę URI w wygenerowanym kodzie:

<PropertyGroup> 
    <AssemblyVersion>1.0.0.0</AssemblyVersion> 
    <AssemblyPublicKeyToken>[YOUR_PUBLIC_KEY_TOKEN]</AssemblyPublicKeyToken> 
</PropertyGroup> 
+1

Skąd to wiedziałeś? To jest takie ... bardzo ezoteryczne. nie jest to oficjalnie obsługiwane, ale działa! – user195275

+0

Nie podoba mi się to rozwiązanie, co jeśli zmienię wersję (brak automatycznego refaktora) lub mam inny klucz w mojej maszynie do debugowania i serwerze kompilacji? –

+0

Pracowałem nad tym problemem już od ponad tygodnia i bardzo cierpiałem! Twoja odpowiedź zadziałała dla mnie jak urok i bardzo pomogła! Dziękuję Ci!! (zwróć także uwagę na [tę stronę] (https: //alexfeinberg.wordpress.com/2014/11/08/microsoft-mechanism-to-load-wpf-resources-is-broken-looking-for-a-better-title /), który zacytował ten wątek) –

1

Zmagam się z tym w VS2012. Nie mogłem znaleźć rozwiązania Riccardo do pracy w tym środowisku. Ten wariant jego kodem ...

_contentLoaded = true; 
var assemblyName = GetType().Assembly.GetName(); 
Application.LoadComponent(this, new Uri(String.Format("/{0};v{1};component/CustomersFrame.xaml", assemblyName.Name, assemblyName.Version), UriKind.Relative)); 

... nie rozwiąże problemu „nie może zlokalizować źródło”, ale potem hit następujący błąd nieco dalej wzdłuż w elemencie dziecka: „Nie można zarejestrować nazwie obiektu. Nie można zarejestrować zduplikowanej nazwy "szukaj" w tym zakresie. "

Rozwiązanie Aarona Martena działa dla mnie. Niestety nie mogę komentować ani przegłosować, ale nie mam przedstawiciela.

1

Możesz również przekazać parametr/p: AssemblyVersion = $ version do procesu msbuild, jeśli kompilacje są zautomatyzowane.

+0

Pracowałem nad tym problemem teraz dla ponad tydzień i bardzo cierpiałem! Twoja odpowiedź zadziałała dla mnie jak urok i bardzo pomogła! Dziękuję Ci!! (zwróć też uwagę na [tę stronę] (https://alexfeinberg.wordpress.com/2014/11/08/microsoft-mechanism-to-load-wpf-resources-is-broken-looking-for-a-better-title/), który cytował twoją odpowiedź) –

+0

I sited my blog – user195275

0

Ten kod, oparty na odpowiedzi Riccardo, pracował dla mnie w VS2010.

Najpierw zdefiniowałem metodę ładującą, którą mogę wywołać z mojego konstruktora XAML.

namespace Utility 
{ 
    public class Utility 
    { 
     public static void LoadXaml(Object obj) 
     { 
      var type = obj.GetType(); 
      var assemblyName = type.Assembly.GetName(); 
      var uristring = string.Format("/{0};v{1};component/{2}.xaml", 
       assemblyName.Name, 
       assemblyName.Version, 
       type.Name); 
      var uri = new Uri(uristring, UriKind.Relative); 
      System.Windows.Application.LoadComponent(obj, uri); 
     } 
    } 
} 

Następnie w konstruktorze dla każdej kontroli XAML, Wymieniłem InitializeComponent() z:

 _contentLoaded = true; 
     Utility.Utility.LoadXaml(this); 
     InitializeComponent(); 

Zauważyłem, że niektórzy z moich wiązań RelativeSource przestał działać, ale udało mi się obejść .

Powiązane problemy