none
Zugriff auf String-Resourcen (XAML) welche zu einer Library gehören RRS feed

  • Frage

  • Hallo,

    ich habe folgendes Problem: Zum Zwecke der Lokalisierung habe ich Strings in ResourceDictionaries in verschiedene XAML-Dateien gepackt. Die Anwendung besteht aus einem Executing-Assembly als Main-Program und mehreren (später c.a. 500) DLLs. Jedes dieser DLL-Projekte soll sein eigenes ResourceDictionary haben. Wenn ich nun aber mit Application.FindResource("einText") versuche, einen ResourceString zu laden, schlägt dies fehl, da das ResourceDictionary NICHT in die Application-Resources gemergt wird. Soweit, so gut.
    Nun handelt es sich bei diesen String i.d.R. um Fehlertexte bzgl. der Datenvalidierung. Da ich mich streng an das ModelViewViewModel-Pattern halten möchte, findet das im ViewModel statt - ich kann kann also per FrameworkElement.Resources nicht zugreifen, da ich dort kein FrameworkElement kenne.

    Nun hatte ich die Idee, dass (dazu muss man wissen, dass jedes DLL-Projekt mit UserControls arbeitet - nicht mit Windows) ich einen EventSetter in einem Style mit dem TargetType "UserControl" erstelle, der das Loaded-Event behandelt. Dort sollen dass die Resources des UserControls mit den Applicationresources gemergt werden. Da ich das gleiche bereits mit DataGrid gemacht habe - was tadellos funktioniert - war ich sehr erstaunt, dass das bei UserControls nicht funktioniert - der Debugger hält in der entsprechenden Methode nicht an.

    Das Ganze sieht so aus:

        <Style TargetType="{x:Type UserControl}">
            <EventSetter Event="Loaded"  Handler="UserControlLoaded"/>
        </Style>

    und im Code-behind:

        public partial class UserControlResources
        {
            public void UserControlLoaded(object sender, RoutedEventArgs e)
            {
                if (!(sender is UserControl))
                {
                    return;
                }
                UserControl uc = sender as UserControl;
                Application.Current.Resources.MergedDictionaries.Add(uc.Resources);
            }
        }

    Es ist mit schleierhaft, warum das - zur Laufzeit - nicht funktioniert. Ich habe zum Spaß mal in dem Style die Hintergrundfarbe auf Rot gesetzt um zu schauen, ob sich denn überhaupt etwas tut. Zur Designzeit sind dann die UserControls tatsächlich Rot - nur zur Laufzeit nicht.

    Mir wäre aber auch schon geholfen, wenn mir jemand eine Alternative aufzeigen könnte, wie man aus einer anderen Assembly an die Resource-Strings kommt.

    Wenn das jetzt alles zu wirr ist, bitte ich schon mal um Verzeihung ;-) Aber ich arbeite da jetzt schon den ganzen Tag dran und komme irgendwie von Hölzchen auf Stöckchen - aber keinen Schritt vorwärts.

    Vielen Dank

    Detlef

    Montag, 4. Februar 2013 17:10

Antworten

  • Hallo Carl,
    danke für die Antwort. Ich hatte zwar auch schon an .resx gedacht - allerdings war mir die Vorgehensweise über XAML und LocBaml sehr sympathisch. Das liegt einfach an der Historie der Anwendung. Es ist nämlich nicht so, dass wir dabei sind, eine neue Anwendung zu erstellen. Die existiert nämlich. Ursprünglich war es mal Borland C++. Wir haben sie dann in mühevoller Arbeit nach Winforms C++/CLI portiert. Und weil WPF /Winforms so wunderbar unter einem Dach laufen können, werden wir nun nach und nach die Programme in C# und WPF neu machen. Und von Beginn an hatze die Software einen eigenen Übersetzungsmachnismus für Sprachen, den wir auch bei WinForms beibehalten haben. Und genau dieser Mechanismus (und auch das ganze drumherum bis zur selbst geschriebenen Übersetzungssoftware) ist es, der recht gut zu XAML/LocBaml passt. Wegen Wiederverwendung der vorhandenen Übersetzungen und so. Naja, langer Rede kurzer Sinn: Ich möchte diesen Weg weiter  gehen und habe mittlerweile einen vielversprechenden Weg gefunden, die Resourcen der Application hinzuzufügen (und auch wieder zu entfernen, wenn sie nicht mehr gebraucht werden). Die Grundidee ist dabei gar nicht so kompliziert: Da wo ich die Assembly in der EXE lade, erzeuge ich ja auch die Instanz des gewünschten Controls. Dessen Resourcen füge ich dann der Application hinzu. Dann müssen die Anwendungsentwickler halt beachten, dass ihre UserControls diese Resourcen auch haben.

    Trotzdem danke für Deine Mühe. Hilfreich war es ja allemal :)

    Gruß

    Detlef

    • Als Antwort markiert Detlef Ernst Dienstag, 5. Februar 2013 12:48
    Dienstag, 5. Februar 2013 12:48

Alle Antworten

  • Hallo Detlef,

    schaue dir das mal an, wird recht gut erklärt. Wenn du nicht weiterkommst dann melde dich nochmal ;-).

    http://msdn.microsoft.com/de-de/library/vstudio/ms788718.aspx

    Darüber hinaus gibt es noch weitere Möglichkeiten, kommt darauf an was du erreichen möchtest

    Gruß Carl

    Montag, 4. Februar 2013 19:48
  • Hallo Carl,

    danke für die Antwort. Das ist ja das, was ich machen will. Nur, dass bei mir die Anwendungsarchitektur etwas anders ist. Und es geht nicht um die Texte der Controls - das funktioniert. Es betrifft die Texte, die z.B. Fehlermeldungen für ValidationRules beschreiben - also nicht an einem Control hängen. Das Szenario sieht so aus, dass ich ein Hauptprogramm (eine EXE) habe. Dieses Programm hat ein Menü, in welchem die einzelnen Programmmodule (DLLs) per Assembly.LoadFrom() geladen werden werden. Zu jedem DLL-Projekt gehört eine Resource-XAML. Da stehen dann u.a. die Strings drin:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:system="clr-namespace:System;assembly=mscorlib">
        <system:String x:Key="PasswordRequired" x:Uid="PasswordRequired">Es muss ein Passwort angegeben werden!</system:String>
    </ResourceDictionary>

    Nun gibt es z.b. eine BindingGroup mit ValidationRule:

        public class PasswordValidationRule : ValidationRule
        {
            public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
            {
            :
            :
                if (data.IsNew && String.IsNullOrEmpty(data.Password))
                {
                    return new ValidationResult(false, Application.Current.TryFindResource("PasswordRequired"));
                }
                return ValidationResult.ValidResult;
            }
        }

    Application.Current.TryFindResource() gibt null zurück, da der String "PasswordRequired" nicht in den ResourceDictionaries von Application gefunden wird. Ich muss also entweder dafür sorgen, dass obiges ResourceDictionary den Dictionaries der Application hinzugefügt wird oder es gibt noch eine weitere Möglichkeit außer Application.Current.FindResource() auf den String zuzugreifen.
    Aufgrund der Größe der Anwendung möchte ich nicht jede Resource-XAML in das Hauptprogramm einbinden. Außerdem ist das eine Sache, die man leicht vergisst. U.U. merkt das sogar erst der Anwender - was dann nicht so lecker wäre. Auch von einer zentralen Resource-XAML bin ich nicht so begeistert - die dürfte recht groß und unübersichlich werden.

    Gruß

    Detlef

    Dienstag, 5. Februar 2013 08:25
  • Hallo Detlef,

    ich dachte mir schon, dass dir die Größe deiner Anwendung Sorgen bereiten wird... wenn es nur darum geht Strings in einer geeigneten Form vorzuhalten, nehme ich nach wie vor noch Resources.resx files, die ich in einer Satellitenassembly vorhalte. Das funktioniert bei mir in sehr großen Projekten reibungslos, bietet die Lokalisierung und auch Fallback-Mechanismen, sodass deine Anwendung immer funktioniert. Ich finde das ist noch die eleganteste und einfachste Art eine Anwendung zu lokalisieren(sofern es um Strings geht) und bringt noch eine Menge weiterer Benefits mit ;-). Übrigens gibt es dazu auch einige Tools um solche mehrsprachigen Resourcen elegant zu bearbeiten...

    Schau mal hier, da findest du einen guten Einstieg:

    http://msdn.microsoft.com/de-de/library/z68135h5.aspx

    Wenn du damit nicht weiterkommst, dann melde dich noch mal.

    Gruß Carl

    Dienstag, 5. Februar 2013 10:27
  • Hallo Carl,
    danke für die Antwort. Ich hatte zwar auch schon an .resx gedacht - allerdings war mir die Vorgehensweise über XAML und LocBaml sehr sympathisch. Das liegt einfach an der Historie der Anwendung. Es ist nämlich nicht so, dass wir dabei sind, eine neue Anwendung zu erstellen. Die existiert nämlich. Ursprünglich war es mal Borland C++. Wir haben sie dann in mühevoller Arbeit nach Winforms C++/CLI portiert. Und weil WPF /Winforms so wunderbar unter einem Dach laufen können, werden wir nun nach und nach die Programme in C# und WPF neu machen. Und von Beginn an hatze die Software einen eigenen Übersetzungsmachnismus für Sprachen, den wir auch bei WinForms beibehalten haben. Und genau dieser Mechanismus (und auch das ganze drumherum bis zur selbst geschriebenen Übersetzungssoftware) ist es, der recht gut zu XAML/LocBaml passt. Wegen Wiederverwendung der vorhandenen Übersetzungen und so. Naja, langer Rede kurzer Sinn: Ich möchte diesen Weg weiter  gehen und habe mittlerweile einen vielversprechenden Weg gefunden, die Resourcen der Application hinzuzufügen (und auch wieder zu entfernen, wenn sie nicht mehr gebraucht werden). Die Grundidee ist dabei gar nicht so kompliziert: Da wo ich die Assembly in der EXE lade, erzeuge ich ja auch die Instanz des gewünschten Controls. Dessen Resourcen füge ich dann der Application hinzu. Dann müssen die Anwendungsentwickler halt beachten, dass ihre UserControls diese Resourcen auch haben.

    Trotzdem danke für Deine Mühe. Hilfreich war es ja allemal :)

    Gruß

    Detlef

    • Als Antwort markiert Detlef Ernst Dienstag, 5. Februar 2013 12:48
    Dienstag, 5. Februar 2013 12:48