Laden...
S
sth_Weird myCSharp.de - Member
Dipl.Ing IT (BA) BaWü Dabei seit 17.01.2007 469 Beiträge
Benutzerbeschreibung

Forenbeiträge von sth_Weird Ingesamt 469 Beiträge

25.11.2014 - 10:05 Uhr

Hallo,
Ich stehe vor folgendem Problem:
Ich habe mir ein Style geschrieben für diverse, an vielen Stellen verwendete Spezial-Buttons in meiner Applikation (für Speichern, Löschen, Hinzufügen etc.). Diese sollen immer ein Icon und einen festen Text haben. Beispiel:

<Style x:Key="AddButton" TargetType="{x:Type Button}">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="Background" Value="{StaticResource ButtonBgColor}" />
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Name="ButtonStackPanel"  Orientation="Horizontal">
                        <Image Source="{StaticResource IcoAdd}" HorizontalAlignment="Left" Margin="8,0,0,0" Height="24" Width="24" />
                        <Label Content="Hinzufügen" HorizontalAlignment="Center" />
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Das funktioniert soweit so gut. Nun habe ich aber hier explizit festgelegt, dass Icon und Text nebeneinander angezeigt werden sollen (StackPanel mit Orientation = Horizontal).
Ich würden gerne einen zweiten Button haben mit denselben Eigenschaften und Farben etc., aber Icon und Text sollen untereinander angezeigt werden.
Beim googeln bin ich auf viele Beispiele gestoßen wie man Styles vererben kann (BasedOn-Tag) und dann einzelne Properties überschreiben, leider sind das immer nur die Basis-Properties (z.B. BackgroundColor oder sowas) die der TargetType schon selber hat. Ist es irgendwie möglich, meinen Style oben abzuleiten und die Orientation des StackPanels zu überschreiben???
So geht es scheinbar nicht:

<Style x:Key="AddButtonV" TargetType="Button" BasedOn="{StaticResource AddButton}" >
        <Setter Property="ButtonStackPanel.Orientation" Value="Vertical"></Setter>
    </Style>

Ich habe noch Lösungen gefunden, die mit DynamicResource arbeiten oder aber mit AttachedProperties...oder ich könnte ein von Button abgeleitetes UserControl für die Spezialbuttons schreiben.
Ich würde aber gern wissen ob es nicht auch irgendwie einfacher mit dem Weg oben geht.

gruß & thx
sth_Weird

12.11.2014 - 09:59 Uhr

@Jacyrio
Ja was die Lösungswege angeht, da ist WPF nicht gerade intuitiv...bei WinForms gab es immer nur "einen" Weg zum Ziel, mir scheint WPF bietet da zig Wege an und manchmal hängt es von diesem und jenem Kriterium ab ob ein Weg der "richtige" ist oder nicht. Selbst wenn man sich unterschiedliche Tutorials, sei es im Netz oder in Büchern, anguckt, nutzt scheinbar jeder für die gleiche Aufgabe unterschiedliche Ansätze (und verteufelt ggf die alterniven Ansätze).

Zu deinem Ansatz:
Das Kind mit dem Parent zu verknüpfen möchte ich allerdings nicht, auch wenn es "nur" im ViewModel ist. Das Kind-ViewModel sollte meiner Meinung nach das Parent-ViewModel nicht kennen, denn das schränkt die (Wieder-)Verwendung in anderen Kontexten doch stark ein.

Wenn sich in nächster Zeit kein WPF Guru hier meldet und mich eines besseren belehrt, wird mein erster Versuch mal sein, den Command des Kind-ViewModels von außen zu setzen...

gruß
sth_Weird

12.11.2014 - 08:43 Uhr

Hmm, dann ist das mit den expliziten Namen wohl leider der vorgesehene Weg 😕
Danke für die Antwort

gruß
sth_Weird

12.11.2014 - 08:40 Uhr

Hallo witte,

ob das mit dem Parent/Child-ViewModel so passt war ja auch nicht die Frage.
Aber passt das denn dann so (nach MVVM und WPF Gedanke) , wenn mein Main/Parent-ViewModel ein Command des Child-ViewModels setzt? Oder müsste ich eher auf ein NotifyChanged-Event hören (oder ist das wieder zu sehr der WinForms Gedanke)? Oder was ganz anderes machen?
Es ist ja nicht so, dass nur ein Weg zum Ziel führt...ích möchte halt nur den richtigen, schönen gehen 😉

gruß
sth_Weird

11.11.2014 - 12:41 Uhr

Hallo,

ich beiße mir gerade die Zähne daran aus, wie ich nach MVVM Konzept Unter-ViewModels mit dem Haupt-ViewModel kommunizieren lasse...

Ich habe ein View auf welchem sich diverse UserControls befinden.
Die UserControls haben ViewModels als DataContext, das View selbst hat auch ein ViewModel, in diesem ViewModel sind Verweise auf die ViewModels der anderen UserControls.
Nun habe ich ein UserControl, das aus WinWorms-Sicht eine Art Auswahldialog darstellt, wenn man dort auf einen Button klickt dann würde ein Event geworfen "Auswahl getroffen" mit der Auswahl als Parameter.
Für selbiges versuche ich ein WPF/MVVM UserControl zu erstellen.
In meinem WPF UserControl habe ich den Button an ein Command gebunden.
Wie gelangt nun die Information, dass in meinem UserControl der Button geklickt wurde, richtig in mein Main-ViewModel?
Beim googeln bin ich auf folgende Ansätze gestoßen:
-> Ich setze den Command des Buttons über ein Property von außen, d.h. das MainViewModel setzt den Command des UserControl-ViewModels
-> Verwenden von DependencyProperties
-> Der Button/Command setzt ein Property "Selection" (Auswahl) und das MainViewModel hängt sich an das NotifyPropertyChanged dieses Properties
-> Komplexes Nachrichten-Service-System zur Kommunikation zwischen verschiedenen ViewModels, scheint mir hier etwas zu komplex da alle UserControls ja im gleichen View sind?

Am einfachsten scheint mir die Lösung mit dem Command von außen setzen.
Dann hätte ich quasi im MainViewModel ein Propery myUserControlViewModel mit dem ViewModel des UserControls, und ein ICommand SelectionChanged, und ich würde beim Erstellen des MainViewModels machen: myUserControlViewModel.OnSelectionChanged = SelectionChanged (alles Commands!).
Wäre das aus MVVM Sicht so richtig?

Für den Ansatz, dass der ButtonClick ein Property setzt, an das ich mich binde:
Ich wüsste hier schon, wie man z.B. in einem DataTemplate für das MainViewModel eine TextBox an diese Auswahl bindet, aber wie ich die gleiche Info im Code-behind an ein Property binde anstelle an eine TextBox, da weiß ich nicht weiter 😦.

gruß & danke
sth_Weid

07.11.2014 - 09:43 Uhr

Ich weiß nicht genau ob ich das Problem richtig verstanden habe da ich auch selber noch totaler WPF Neuling bin (und wahrscheinlich bald vor einem ähnlichen Fall stehe wie du jetzt), aber du schreibst doch ganz oben, dass der Sender so aussieht:
System.Windows.Controls.TabItem Header:<Namespace>.ArtikelList Content:<Namespace>.ArtikelList
Also diese "ArtikelList" klingt doch schon wie das Objekt das du suchst oder? Dann müsstest du doch über senderTabItem.Content das Objekt haben und dieses müsstest du dann aus der ObservableCollection löschen (?).

gruß
sth_Weird

07.11.2014 - 09:20 Uhr

Hallo,
ich stehe gerade vor folgendem Problem:
Ich möchte ein Anzeige/Editier-Formular für diverse eigene Klasse erstellen.
Links ist ein Baum, dort kann ich ein Objekt auswählen, rechts kommt dann beim Anklicken eines Objekts eine (je nach Einstellung editierbare) Detailansicht.
Ich verwende hierzu das MVVM Pattern.
Für jede Klasse habe ich ein ViewModel, das kommt im TreeView und auch in der Detailanzeige zum Einsatz. Zu Anzeige selber verwende ich zur Zeit DataTemplates und einen DataTemplateSelector.
Für eine einfache Klasse mit primitiven Datentypen etc. ist das alles ja sehr einfach und klappt prima.
Nun haben einige Klassen aber Properties mit nichtprimitiven Datentypen, genauer gesagt vom Typ "Klasse". In meinem Editier-Formular soll dann eine ComboBox erscheinen, mit einer Auswahl an Instanzen dieser Klasse., die man dem Property dann zuweisen kann.
Hier habe ich mir folgende Möglichkeiten überlegt und würde gerne von WPF Erfahreneren wissen, welche Lösung denn besser ist.

  1. Ich bleibe beim bisherigen Ansatz. Ich könnte theoretisch im gleichen ViewModel ein Property PossibleValues anbieten, das bei Bedarf alle Auswahlmöglichkeiten anbietet (da ich die Datenanbindung im ViewModel habe, ist es einfach dort Daten nachzuladen). Diese Auswahl brauche ich im TreeView oder nur zur Anzeige nicht. "Stört" das, wenn es trotzdem drin ist? Ich meine das ViewModel ist ja theoretisch dafür gedacht in mehreren Views verwendet weren zu können, dass nicht in jedem View alle Properties wirklich angebunden werden ist eigentlich logisch...
  2. Ich mache zum Editieren ein neues ViewModel. Hier ist dann aber das "Problem", dass ich im Baum einen Eintrag selektiere, aber das ViewModel dort wird nicht für die Detailanzeige verwendet, sondern ich muss mir ein anderes erstellen (das ist durchaus machbar, aber da ich im Baum darstellen will, wenn ein User im Detailfenster was geändert hat, müssten sich die ViewModels irgendwie "kennen"). Dafür macht aber jedes ViewModel nur das, wofür es geschaffen wurde, und ist keine "eierlegende Wollmilchsau"
  3. Vielleicht sind hier die DataTemplates an sich ein falscher Ansatz und ich sollte lieber ein UserControl erstellen, welches dann "mehrere" ViewModels haben kann, das des zu editierenden Objekts (original so wie es auch im TreeView verwendet wird) und die Liste der Auswahlmöglichkeiten. Da das UserControl aber sonst keine Funktion (ich will ja nur die Daten anzeigen/editieren und habe keine Hintergrundfunktionalität) hätte wäre es etwas mit Kanonen auf Spatzen geschossen.

Also ich denke alle Wege führen zum Ziel, deshalb würde mich nur interessieren, welchen Ansatz ihr nehmen würdet und warum? Es geht weniger darum was schneller geht oder einfacher zu implementieren ist oder so, sondern welcher Ansatz am ehesten dem Sinne der Erfindung WPF oder MVVM entspricht.

gruß & danke
sth_Weird

05.11.2014 - 11:05 Uhr

Hallo,

Ich habe in meiner Dll ein ResourceDictionary mit DataTemplates angelegt.
In einer anderen Dll gibt es eine Art zentrale Sammelstelle für alle DataTemplates. Dort kann ich ein Template registrieren in der Art

DataTemplates.Register(Type type, DataTemplate template);

Ich habe aktuell das ResourceDicionary in die Resources meiner Einstiegsklasse (UserControl) eingefuegt. Dann kann ich ja im C# Code mit

FindResource(string key)

nach meinem Template suchen.
Mir missfällt an dem Ansatz, dass ich nach dem Key in Form eines Strings suchen muss. Ändere ich den Key im ResourceDictionary, dann wird die Resource nicht mehr gefunden, das fällt aber erst zur Laufzeit auf.
Beim googlen bin ich aber leider immer nur auf diese Lösungsvariante gestoßen.
Bin noch recht grün hinter den Ohren was WPF anbelangt, gibt es Alternativen zur obigen Vorgehensweise?

gruß & danke
sth_Weird

17.10.2014 - 09:40 Uhr

Hallo,
Folgendes Problem:
VS 2012 auf Rechner 1 ist auf deutsch eingestellt, VS 2012 auf Rechner 2 ist auf englisch eingestellt. Auf Rechner 2 compiliert ein und dasselbe Projekt nicht, das auf Rechner 1 erstellt wurde. Es meckert im resx File die Zeichenfolge "Strg+..." an (es ist an der Stelle ein Tastenkürzel hinterlegt).
Herausgefunden haben wir, dass es tatsächlich an der Spracheinstellung liegt. Die englische Entwicklungsumgebung erwartet hier wohl "Ctrl" statt "Strg". Stellt man VS auf Rechner 2 auch auf Deutsch um, compiliert das Projekt auch hier. Abgesehen davon, dass ich das unverständlich finde, dass die Sprache der Entwicklungsumgebung das Compilieren beeinflusst,...
Gibt es da irgendwo eine Einstellung, damit es auf beiden Rechnern compiliert, ohne dass beide dieselbe Sprache in der Entwicklungsumgebung benutzen müssen?
gruß & thx
sth_Weird

10.10.2014 - 09:44 Uhr

Ja, ich denke ich werde es auch über Parent/Child Relationships machen. Das hab ich bisher immer so gemacht und ich bin da gut mit klargekommen. Man fühlt sich nur immer, wenn was "neues" auf den Markt kommt, irgendwie genötigt oder schöner ausgedrückt verführt dazu, es auszuprobieren, man will ja fortschrittlich sein 😉
Für meinen Fall ist das Verwenden der HierarchyID aber so wie ich das sehe eher ein unnötiger Mehraufwand, da ich von den Vorteilen keinen Gebrauch machen würde...
Falls einer trotzdem noch ein C# Beispiel fände da mit HieraryIDs arbeitet, darf er es gerne noch posten 😃

Danke für eure Rückmeldungen!

Gruß
sth_Weird

10.10.2014 - 09:23 Uhr

das war's was ich gesucht hab...danke!

06.10.2014 - 13:40 Uhr

verwendetes Datenbanksystem: SQLServer 2008

hi,
Ich muss gerade ein paar neue Datenbanktabellen erstellen. Diese müssen eine Art TreeView abbilden, also mit Hierarchien. Bisher habe ich das immer mit Parent/Child Beziehungen gemacht (in früheren SQLServer Versionen gab es ja "nichts" anderes) und bin gut damit klargekommen. Nun bin ich über HierarchyID gestolpert. Die hört sich anfürsich sehr gut an, WENN man mit StoredProceedures arbeitet. Das geht aber nicht (ist einfach so und soll hier auch nicht diskutiert werden).
Deshalb meine Frage ob schonmal jemand versucht hat Tabellen mit HierarchyIDs rein von C# aus zu verwalten (rein über SQL-Queries und manuell erstellten Datenklassen, es ist kein Entity Framework dahinter). Also nicht nur Anzeigen (das sollte machbar sein und ich denk sogar einfacher als früher), sondern auch und vor allem neue Knoten einfügen, Knoten verschieben (inkl. Kind-Knoten), Knoten löschen.
In den Internet-Beispielen geht halt alles über StoredProceedures und da werden teils Declares und Curser verwendet (weil z.B. das Verschieben eines Knotens die Kindknoten nicht mitverschiebt und wenn man einen Parent Knoten löscht dann hat man verwaiste Kinder weil die nicht automatisch mitgelöscht werden können).
Ich könnt mir nur vorstellen mehrere SQL Abfragen zu machen und ne Transaction drumzupacken. Alles in allem klingt es aber nach SEHR viel Aufwand und viele Stellen an denen man was vergessen oder falsch machen kann. Ich überlege ob es nicht einfacher wäre weiter auf die Parent/Child Relationships zu setzen. Dieses Plus an Funktionalität bei Abfragen brauche ich eigentlich in meinen Anwendungen so nicht unbedingt bzw. ist nichts was ich nicht mit einfachem C# Code / SQL Statements lösen könnte. Es wär halt schön die angeblich sehr gute Performance nutzen zu können.
Wäre schön, wenn jemand Feedback zu diesem Thema hätte!

thx
sth_Weird

24.09.2014 - 11:52 Uhr

Ich steh grad auf dem Schlauch...
Ich habe eine Funktion RegisterDataTemplate(Type type, DataTemplate template), diese soll für einen bestimmten Datentyp "type" ein DataTemplate in meinem Template-Dictionary registrieren.
Nun möchte ich aber einschränken, dass nur solche Typen verwendet werden dürfen, die ein bestimmtes Interface implementieren.
Kann ich das schon in der Funktionsdefinition einschränken (ich meine das schonmal gesehen zu haben, bin mir aber nicht sicher,...
Zur Klarstellung nochmal: Ich möchte nicht haben RegisterDataTemplate(IMyInterface myObject, DataTemplate template)!!! Es geht nicht um ein bestimmtes Objekt, sondern den Typ eines Objekts. Also bräuchte ich eher sowas wie (Type type where type implements IMyInterface ..) in meinem Funktionsaufruf...
Kann mir jemand sagen ob das überhaupt geht und wenn ja wie (oder wo ich es nachlesen kann wie es geht), oder auch einfach ob es eben nicht geht...

Gruß & Danke
sth_Weird

01.08.2014 - 09:00 Uhr

ich meinte die Pixel-Werte die in der Anzeige unten rechts stehen... Width, X-Position, Y-Position, Cursor-Dist. etc...das ist ja alles in Pixel und die muss das Tool doch irgendwie auch berechnen können?
Nuja, guck mir jetzt mal das TTF Format an, vielleicht hilft mir das ja weiter...

31.07.2014 - 12:44 Uhr

ich möchte theoretisch eine einfachere Variante dieses Tools nachprogrammieren (ich muss nur an die Pixel-Werte kommen, eine GUI dazu oder den c-Output brauche ich nicht (dafür aber andere Funktionen die das Tool nicht mitbringt, z.B. dass ich die Font aus einer Datei lade und diese NICHT installieren muss).
emWin Font Converter
oder (scheint fast so als wäre das der gleiche...)
emWin: Font Converter and Editor

gruß
sth_Weird

31.07.2014 - 10:25 Uhr

hallo,
ich möchte eine Schriftart laden (TTF, muss nicht installiert sein), deren unterstützte Zeichen ermitteln und dann die Breite jedes Zeichens in Pixel, abhängig von der Schriftgröße (auch in Pixel) ermitteln.
Die FontFamily lade ich mit dem System.Windows.Media Namespace, darüber komme ich auch an das GlyphTypeface und die CharacterMap. Leider sehe ich hier keine Möglichkeit, an eine Breite in Pixeln zu kommen. So ein Glyph hat zwar Properties wie AdvancedWidth etc (was sich schon genau nach dem anhört was ich brauche), aber da kommen immer Doubles zurück und ich habe bisher keine sinnvolle Umrechnung in Pixel gefunden, es kommen immer seltsame Werte raus die nicht passen. Ich kenne auch die Variante mit dem System.Windows.Forms und System.Drawing Namespace, da gibt es dann ja TextMetrics und (graphics-Objekt).MeasureText, aber hier wiederum habe ich keine Möglichkeit gefunden an die CharacterMap zu kommen (und graphics-Objket hab ich auch nicht, ich will den Text auch nicht zeichnen oder so ich will nur die geräteunabhängigen Pixel-Breiten eines Zeichens ausgeben)
Hat jemand nen Tipp wie man das am besten hinbekommt?
Beim googeln bin ich nicht weiter gekommen, dort wird immer entweder die CharacterMap gesucht ODER die Zeichenbreite.

Mir fiele nur ein die beiden Varianten zu kombinieren (also CharacterMap mit dem einen FontFamily Objekt bestimmen und dann die FontFamily nochmal im anderen Namespace laden und mit TextMetrics die Breiten berechnen), ich will aber noch nicht glauben dass es da nicht eine bessere Lösung gibt und hoffe deshalb auf Tipps.

gruß & thx
sth_Weird

14.07.2014 - 09:38 Uhr

Ja, wenn es sich nur um eine einfache z.B. Kontaktverwaltung oder ähnliches handeln würde, die sich "nie" ändert und ne fixe GUI ohne Variationsmöglichkeiten hat, dann würde ich es auch so machen (man muss ja auch immer Aufwand/Nutzen betrachten). Das ganze ist halt in meinem Projekt etwas komplexer und mit Weitsicht (Erweiterbarkeit, Sharing/Wiederverwertung von ViewModels und Views auch in anderen Teilen der Applikation etc.).

gruß
sth_Weird

11.07.2014 - 11:42 Uhr

Sorry, aber alles in ein ViewModel zu packen finde ich nicht richtig. Ich bin der Meinung, dass man verschiedene "Anwendungefälle" auch in unterschiedliche ViewModels packen sollte.
Man stelle sich vor, ein Baum stellt Mitarbeiter eines Zoos dar. Ein Mitarbeiter hat z.B. ein persönliches Profil mit Lieblingstier etc, dann (nur für den Chef und den Mitarbeiter selbst sichtbar) Personaldaten (Gehalt etc.) und dann noch eine Arbeitszeitnachweistabelle, einen Urlaubsplan und vielleicht nochmal was... Jedes dieser "Gebiete" ist Teil des Models eines Zoo-Mitarbeiters und ich könnte mir vom Baum aus jedes dieser "Gebiete" in einem eigenen DetailsView anzeigen lassen (Oder ich habe drei unterschieliche Applikationen die alle den gleiche Baum verwenden aber nur EINES der DetailsViews anzeigt, je nach Applikationszweck...oder eine Applikation die keinen Baum hat aber die DetailsViews haben soll).
Willst du dann wirklich vorschlagen, dass ich für den Baumknoten, der diesen Mitarbeiter repräsentiert, und ALLE der möglichen DetailsViews EIN ViewModel verwende, das alle Properties und Commands anbietet? Mir fehlt hier der Gedanke der Modularität (Single responsibility/Separation of concerns), dadurch dass ich in einem ViewModel dann alle Properties und Commands habe die ich irgendwo brauche verheirate ich doch die ganzen, prinzipiell unabhängigen Anwendungsfälle/Views miteinander...

gruß
sth_Weird

07.07.2014 - 10:27 Uhr

Danke für die Antwort, habe es jetzt aber anders gelöst...
Ich habe für alle ViewModels ein Property ItemType hinzugefügt, dann setze ich das ContextMenu über einen DataTrigger, hier beispielhaft:

<DataTrigger Binding="{Binding ItemType}" Value="Menu">
               <Setter Property="ContextMenu" Value="{StaticResource CtxMenuMain}" />
</DataTrigger>
<DataTrigger Binding="{Binding ItemType}" Value="Leaf">
     <Setter Property="ContextMenu" Value="{StaticResource CtxMenuLeaf}" />
</DataTrigger>

Es funktioniert 😃

gruß
sth_Weird

04.07.2014 - 11:11 Uhr

hallo,
wieder mal ein WPF Problem...

Ich möchte in meinem TreeView abhängig vom (Hierarchial)DataTemplate ein ContextMenu anzeigen. Das wäre an für sich ganz einfach, wenn ich das ContextMenu an das jeweilige DataTemplate anhänge (also an ein Anzeigelement).
Nun das ABER: Ich möchte dass, wenn ich mit der rechten Maustaste das ContextMenu aufrufe, das TreeViewItem auch selektiert wird (das ist ja leider (warum auch immer) kein Standard-Verhalten). Dafür habe ich mir ein Behaviour für TreeViewItem geschrieben, welches beim treeViewItem.ContextMenu.ContextMenuOpening den Eintrag selektiert.
Aber ContextMenu ist hier immer null. Was auch logisch ist, denn das ContextMenu ist ja im Template definiert und hängt nicht direkt für das TreeViewItem.

Wie kann ich das lösen, also einerseits das Behaviour haben andereseits das DataTemplate-abhängige Menu?

Mein erster Gedanke wäre, dass ich die ContextMenues als TreeView Resourcen definiere. Im ItemsContainerStyle kann ich dann darauf verweisen, aber wie unterscheide ich, welches ContextMenu ich nehme? Kann ich im XAML sowas machen wie "wenn dein DataTemplate = xyz ist dann verwende MenuA, sonst MenuB"? Oder ist hier das richtige Stichwort IValueConverter?
Oder habe ich das Behaviour für die gewünschte Funktionalität im TreeViewItem falsch angesiedelt, könnte/sollte man es dem ContextMenu attachen?

gruß & thx
sth_Weird

04.07.2014 - 10:51 Uhr

nee es ist schon die selbe Instanz des MODELS, aber das ViewModel für den Baum bietet nur einen für den Baum geeigneten Namen an. Das Model selber hat natürlich viele Eigenschaften mehr, die aber für den Baum nicht relevant sind. Diese Properties biete ich im Details-ViewModel an. Natürlich könnte ich auch ein einziges ViewModel machen und im Baum halt nur das eine relevante Property binden, im Detailsview die anderen relevanten Properties. So eine Art "eierlegende Wollmilchsau" ViewModel möchte ich aber eigentlich nicht.
Ich werde es nun so lösen, dass ich einfach eine Ebene "obendrauf" setze, also eine Klasse die alle ViewModels der Anwendung kennt und auf INotifyPropertyChanged Events reagiert. Also doch so ne Art Mediator. Es gibt zwar sicher Lösungen mit weniger CodeBehind, aber deren Realisierung scheinen mit komplexer und es soll ja in endlicher Zeit auch mal was rausplumsen...

gruß
sth_Weird

27.06.2014 - 12:20 Uhr

hmm verstehe nicht so ganz den Zusammenhang deiner Antwort mit meiner Frage...klar hab ich Model, ViewModel, View und Commands fuer die Aktionen (speichern, suchen und so) (und ((Hierarchial)DataTemplates und all so Zeug für die Anzeige)). Das ganze funktioniert ja. Den Code habe ich z.B. hier abgeguckt (der ist in den meisten Beispielen im Netz ähnlich so verkehrt kann er nicht sein):
WPF-Anwendungen mit dem Model-View-ViewModel-Entwurfsmuster

Vielleicht das ganze mal stukturiert (teilweise Pseudocode und unvollständig, ohne setter):

(Model) Klasse Datenklasse: Properties: ID, Name,
(ViewModel) Klasse TreeViewModel: Properties: Anzeigetext {get { return datenklasse.ID+ datenklasse.Name}}
(ViewModel) Klasse DetailsViewModel: Properties: ID {get {return datenklasse.ID}}, Name {get[{return datenklasse.Name}}
..und noch zwei separate Views, einmal der Baum, einmal eine Detailansicht, die zum aktuellen Zeitpunkt noch nichts voneinander wissen.
Das DataTemplate des TreeViewItems ist an den Typ TreeViewModel gebunden. Es wird als Text das Property "Anzeigetext" aus dem TreeViewModel verwendet. Das TreeViewModel hat Commands zum laden/speichern etc. der Daten über einen Command aus/in die Datenquelle, z.B. einer Datenbank.
Die Detailanzeige ist ans DetailsViewModel gebunden, z.B. gibt es eine TextBox die an das Property "Name" des DetailsViewModels gebunden ist. Ändere ich hier was, wandert die Änderung übers ViewModel ins Model. Die Änderung soll auch im Baum sichtbar sein, denn das Name-Property wird ja verwendet um den Anzeigetext zu bilden. Ich muss dem TreeViewModel also irgendwie mitteilen, dass sich was geändert hat, das sich auf es auswirkt.
Die Frage ist nur, wie am besten?
Im Moment bin ich auf dem Mediator-Tripp, auch wenn es im Moment vielleicht eher viel zu pompös scheint, sehe ich hier den Vorteil, soviele Views/ViewModels zu haben wie ich möchte, und vor allem auch wo ich möchte (Framework/Plugin Gedanke), alles wird informiert, wenn sich irgendwo was ändert, was für einen relevant sein könnte.
An ein solches Mediator Pattern hatte ich da gedacht, so ode so ähnlich wird es in den meisten google Treffern beschrieben und die Anwendungsfälle scheinen zu meinen Anforderungen zu passen:
MVVM Mediator Pattern

Ich dachte nur es gäbe vielleicht noch einen einfacheren, aber dennoch wpf-korrekten Lösungsweg (wenn man jetzt mal rein stumpfsinnig vom Aufbau Baum-Detailanzeige ausgeht).

gruß
sth_Weird

27.06.2014 - 10:32 Uhr

-> Visual Studio 2012

hallo,

ich habe ein UserControl mit einer Art "Menuleiste", einem TreeView und einem Detailsview.
Die Menuleiste hat Einträge wie "Suchen", "Editieren", "Speichern". die Menuleiste kennt das ViewModel des TreeViews. (fuer die Items gibt es (Hierarchial)DataTemplates). Dieses ViewModel (also das ViewModel eines Knotens) hat u.a auch ein "Dirty"-Flag, das gesetzt wird, wenn der Anwender am Baum (also direkt am ViewModel des Knotens) was editiert.
Beim Klicken auf "Speichern" sollen die Änderungen am Baum in die Datenquelle (z.B. Datenbank) übernommen werden. Soweit funktioniert das alles. Nun kommt aber noch dazu, dass ein ausgewählter Knoten in einem DetailsView dargestellt werden soll. Dieses hat natürlich ein anderes ViewModel.
Die erste Frage ist nun, wie bekommt das ViewModel des aktuellen Knotens im Baums mit, wenn der Anwender im DetailsView was ändert?
Mir fehlt hier als WPF Neuling noch die Erfahrung was hier "Best Practice" ist.
Ich könnte natürlich im TreeViewModel ein Property SelectedItem haben, welches vom Typ DetailsViewModel ist. Ändert sich dann in diesem DetailsViewModel was, dann könnte ich im TreeViewModel das IsDirty-Flag setzen.
Das wäre meiner Meinung nach der einfachste Weg (dann würde man sich allerdings bei SelectedItem an das spezielle DetailsViewModel binden, d.h. man könnte den Baum einzeln nicht in einem anderen Kontext verwenden).
Beim googlen bin ich auch noch auf das "Mediator" Pattern gestoßen, das wohl auch eingesetzt werden kann, mir scheint es aber für meinen Fall etwas wie mit Kanonen auf Spatzen geschossen.
Und dann gibt es natürlich auch noch das "NotifyPropertyChanged" Event. Dann würde ich quasi die Kommunikation der ViewModels dem UserControl überlassen (wäre das dann in dem Fall auch so eine Art Mediator? -> TreeViewModel postet SelectedItemChanged, UserControl gibt es ans DetailsViewModel weiter, DetailsViewModel postet Änderung, UserControl leitet es an TreeViewModel weiter).
Wie ich das ein oder andere implementieren müsste ist mir so einigermaßen klar, möchte nur wissen was wpf-technisch Best Practice ist, funktionieren würde denke ich alles.

gruß & thx
sth_Weird

20.06.2014 - 11:53 Uhr

hallo,
ich versuche in meinem ValueConverter auf ein Icon zuzugreifen, das sich im selben Prokt in einem anderen Verzeichnis befindet. Leider sagt mir der Compiler immer, er findet es nicht, und ich finde im Moment keinen Anhaltspunkt warum...

Das Bild liegt innerhalb des Projekts unter dem Verzeichnis (das Verzeichnis heißt einfach Resources, die Datei ist nicht eingebettet!!! sondern wurde über Visual Studio 2012 als neue Datei angelegt). In den Einstellungen ist BuildVorgang auf "Resource" eingestellt.
-->
Resources/Images/imageForType1.ico

In meinem ValueConverter, der unter
-->
ValueConverters.TypeToImageConverter.cs
steht, versuche ich folgendermaßen auf das Bild zuzugreifen:


// in der Deklaration
private const string URI_FORMAT = "pack://application:,,,/Resources/Images/{0}";
// in einer Funktion
BitmapImage myBitmap = new BitmapImage(new Uri(String.Format(URI_FORMAT, "imageForType1.ico")));

Compilerfehler:
Die Ressource "resources/images/imagefortype1.ico" kann nicht gefunden werden.

Habe schon danach gegoogelt, trat dieses Problem bei anderen auf sind die Probleme immer:

  • BuildVorgang ist nicht auf Resource eingestellt
    oder
  • Der pack://application...Teil fehlt ganz oder das Bild ist in einer anderen Dll und dann fehlt diese Angabe.
    Wurden diese beiden Dinge bei den anderne korrigiert lief bei denen alles.
    Bei mir stimmt die Einstellung des Buildvorgangs (Resource) und da das Bild im gleichen Projekt liegt brauche ich diesen Dll-Verweis laut Microsoft nicht (in anderen Beispiel-Anwendungen war sie auch nicht dabei). Auf Schreibfehler habe ich natürlich als erstes geprüft 😉
    Projektmappe bereinigen/Neu erstellen, bin/obj Pfade löchen, VS zu und wieder auf - hat alles nichts gebracht.
    Wo könnte der Fehler noch liegen?

gruß & thx
sth_Weird

10.06.2014 - 11:28 Uhr

hmm also der Resharper hat bei uns anfangs schon das ein oder andere durcheinandergewirbelt, aber scheint so als ob man, wenn man mal alles eingestellt und einmal richtig eingerichtet hat, das ganze funktioniert...
K.A. also woran es jetzt wirklich lag der Hinweis mit den Versionen hat's getan 😉, ich freu mich jetzt drüber dass es wieder geht 😃

gruß
sth_Weird

10.06.2014 - 10:39 Uhr

Ja, teilweise haben die Projekte unterschiedliche .NET Versionen (seien es nun die Projekte innerhalb der Projektmappe oder aber Projektverweise außerhalb).
Es ist aber selbstverständlich so, dass ein Projekt mit einer bestimmten .NET Version auf keine Dll mit höherer .NET Version verweist. Es wird immer nur auf Dlls mit der gleichen .NET Version verwiesen oder Dlls mit einer niedrigeren .NET Version (und Client Profile Versionen verwende ich gar keine). Quasi hat mein Startprojekt .NET 4.0 (und die verwiesene Dll die er anmeckert übrigens auch) und es gibt halt in der gleichen Projektmappe noch 2-3 Hilfsprojekte die historisch bedingt noch .NET 2.0 haben.
@Khalid bei MIR zumindest meckert der Compiler sofort wenn ich in mein .NET 2.0 Projekt eine .NET 4.0 Dll verweisen will (Zielframework passt nicht, Version der verwiesenen Dll ist höher als die des Projekts bla bla). Und umgekehrt von .NET 4.0 eine .NET 2.0 sollte meiner Meinung nach kein Problem sein...
Nichtsdestotrotz habe ich trotzdem testweise alle .NET Versionen gleichgezogen und der Compilerfehler ist weg.
???
Die Versionen der Projekte sind schon monatelang ("von Anfang an") so und es gab nie Compiler-Fehler (warum auch, man kann doch in .NET 4.0 Projekten problemlos auf .NET 2.0 Dlls verweisen).
Kann das was mit der Installation vom Resharper zu tun haben? Ich habe projekttechnisch sonst echt nichts gemacht als eine Datei von einem .NET 4.0 Projekt in ein anderes .NET 4.0 Projekt verschoben und einige ganz neue Dateien hinzugefügt...

gruß
sth_Weird

10.06.2014 - 07:56 Uhr

hmm hätte gedacht dass "Projektmappe bereinigen" genau das tut - also bin/obj leeren...habe es jetzt aber nochmal von Hand gemacht und leider nein - der Compilerfehler steht immer noch da.
Danke für die Verweise auf die FAQs, aber nach über 15 Jahren Programmiererfahrung weiß ich wie man Anfänger-Syntaxfehler behebt und einen Verweis richtig erstellt 😉
Interessant ist die Sache mit dem Resharper...den hab ich nämlich seit letzte Woche installiert...vorher ging alles, auch noch ein paar Tage nach der Installation...könnte es trotzdem irgendwas mit dem zu tun haben?

gruß
sth_Weird

06.06.2014 - 12:55 Uhr

Hallo,

Ich habe plötzlich ein seltsames Problem mit einer Using-Direktive (VS 2010).
"Plötzlich", weil es schonmal ging, habe nur ein paar neue Dateien hinzugefügt und ein paar verschoben und die resultierenden Compilerfehler beseitigt und jetzt kracht es auch mir nicht nachvollziehbaren Gründen 😦
Und zwar verweise ich in einem Projekt auf ein anderes Projekt meiner Projektmappe (einfacher Projektverweis).
Der Namespace dieses verwiesenen Projekts sei Abc.
Im verwendenden Projekt steht nun in meiner Klasse "using Abc;" (Die Textvervollständigung bietet dies auch an, was ja darauf schließen lässt, dass der Verweis korrekt erstellt wurde).
ABER wenn ich nun compiliere markiert der Compiler diese using Zeile und meckert: > Fehlermeldung:

Typ oder Namespace Abc konnte nicht gefunden werden (fehlt eine Using....) Es ist der einzige Compilerfehler der angezeigt wird und das Abc-Projekt (und alle anderen Projekte auf die verwiesen wird auch) lässt sich auch einzeln problemlos compilieren.
Ich kann aber in eben der gleichen Klasse mit der "fehlerhaften" using-Direktive ohne weiteres Instanzen von Klassen aus dem Abc-Namespace erstellen (nur zur vollständigen Klarheit: die sind alle in dem einen Abc-Projekt das ich referenziere, in anderen Projekten gibt es keinen Abc Namespace) und die Textvervollständigung bietet mir dann alle Member an.
Ich habe schon probiert:

  • Verweis wieder löschen und neu hinzufügen
  • Projektmappe neu erstellen
  • Visual Studio geschlossen und neu gestartet

Jemand noch ne Idee worans liegen könnte??? Werden noch weitere Infos gebraucht?

gruß
sth_Weird

15.04.2014 - 10:58 Uhr

sorry meine Ausdrucksweise war sehr missverständich...selbstverständlich muss ich letztendlich einen konkreten Typ haben aber der ist auf den ersten Blick halt nicht ersichtlich bzw. es ist nicht notwenig ihr genau zu definieren.

Folgendes Beispiel habe ich im Netz gefunden:


var result = 
from s in aBunchOfWords 
where s.Length == 5 
//Creates a new anonymous type with name/value pairs
select new {Value=s, Length=s.Length, FirstThreeLetters=s.Substring(0,3)};
//Print values 
foreach (var x in result)
Console.WriteLine("Value: {0}, Length:{1}, SubString:{2}", 
x.Value, x.Length, x.FirstThreeLetters);

This prints:
Value: Hello, Length:5, SubString:Hel
Value: World, Length:5, SubString:Wor

wenn ich irgendwo "weiter unten im Code" mit result arbeite dann sehe ich nur dass es var ist. Wenn ich später lustig bin und jetzt keine Length Info mehr will dann lasse ich das einfach in der select-new-Klammer weg, result ändert sich dann natürlich, aber der Typ = var nicht.

Sicherlich, man erspart sich Schreibarbeit, im obigen Fall müsste man sonst ja ne Klasse oder Struktur anstelle von var erstellen...ich denke halt einfach (wenn es keine sonstigen Vorteile hat) dass es auf Kosten der Lesbarkeit geht. Es gibt auch mal Fälle da bekommt man Roh-Code auf Papier vorgelegt oder hat keine komfortable Entwicklungsumgebung sondern nur einen Texteditor und soll dann was analysieren. Da würde ich mir dann konkrete Typen loben...dass der Code außenrum "schön" und eindeutig verständlich ist oder dass eine brauchbare Doku vorliegt, das ist meist Wishful Thinking und man kann sich leider nicht immer verlassen 😦

nichtsdestotrotz, mir reicht soweit schonmal die Antwort, dass es außer schnellerem Tippen (und vielleicht wie im Beispiel oben Code sparen) keine Vorteile bringt... deshalb sehe ich das als gelöst an

gruß
sth_Weird

15.04.2014 - 10:26 Uhr

Hallo,

Ich hoffe das ist keine Grundlagen-Frage, aber ich habe keine SINNVOLLE/ÜBERZEUGENDE Antwort dafür im Netz gefunden...

Ich sehe oft Code in welchem mit var statt mit dem expliziten Datentyp gearbeitet wird. Ich verstehe da oft nicht weshalb. Es gibt sicher sinnvolle Szenarien für die Verwendung von var (Typ des Rückgabewerts steht nicht fest, LINQ etc). Diese "Begründung" für var findet man auch im Netz und das ist mir in dem Zusammenhang auch plausibel.
Warum aber wird so oft var verwendet, obwohl der Typ im Context sehrwohl feststeht und auch garnicht anders sein kann??? Also quasi man ruft ne Funktion auf, deren Rückgabewert vom Typ A ist, schreibt aber trotzdem var instOfA = GetA(); und nicht A instOfA = GetA();
Ich finde der Code wird so viel schwerer lesbar und deshalb frage mich nach den Vorteilen wenn DER TATSÄCHLICHE TYP einer Variablen EINDEUTIG FESTSTEHT? Denn für mich sieht das oft so aus "hmm ich nehm mal var dann brauch ich mir zum jetzigen Zeitpunkt keine Gedanken drüber machen was da überhaupt zurückkommt".

gruß
sth_Weird

14.04.2014 - 13:00 Uhr

dieser Pipeline-Bericht ist sehr interessant und genau das was ich brauche, vorausgesetzt ich hab's richtig verstanden....
Auf mein Problem angewandt: Also durch das Verwenden von GetConsumingEnumerable() in der Task-Funktion erreiche ich, dass meine Task auf neue Telegramme "wartet", solange bis ich für die eingehende BlockingCollection CompleteAdding() aufgerufen habe?
So scheint es laut der Beschreibung zu sein, ich frag nur nochmal nach, da es bei den Bildern im Bericht keine "Pausen" zu geben scheint und die sind ja bei mir wichtig...
Also falls ich das richtig verstanden habe, dann werd ich das mal so machen und der Thread kann als gelöst geschlossen werden 😃

gruß & danke
sth_Weird

14.04.2014 - 11:44 Uhr

halli hallo,

ich habe folgendes Problem:
Meine Klasse erhält in unregelmäßigen Abständen Netzwerk-Telegramme, die sie auswerten soll. Je nach Aktivität kommen die Telegramme mal schneller als meine Routine sie auswerten kann. Teilweise gehören auch mehrere Telegramme inhaltlich zusammen.
Deshalb sammle ich alle ankommenden Telegramme in einer ConcurrentQueue und habe mir eine Task gebastelt, die die Telegramme nacheinander aus dem ConcurrentQueue ausliest und auswertet.
Folgende Problematik: Irgendwann ist der Queue (temporär) leer, der Task sieht sich als beendet an und macht nicht mehr weiter, wenn neue Telegramme ankommen 😦
Gibt es da einen fertigen Mechanismus (.NET 4.5) der die Task wieder "aufweckt" sobald wieder Arbeit für ihn da ist? Im Moment checke ich, wenn neue Nachrichten ankommen, ob die Task noch rennt oder fertig ist, wenn sie fertig ist erstelle ich sie quasi komplett neu. Das finde ich aber eher unschön außerdem habe ich gaaanz selten Fälle in denen dann Telegramme einfach verloren gehen (meine Vermutung ist hier, dass es eine sehr ungünstige Timing-Sache ist zwischen Task-Status abfragen und neuen Messages hinzufügen...wie gesagt es kommt nur gaanz selten vor aber halt doch) 😕

gruß & danke
sth_Weird

07.04.2014 - 10:55 Uhr

danke für die Rückmeldungen,

ich bin das Problem jetzt so umgangen, dass ich beim Aufruf einer Funktion UpdateList (eigene Funktion, die regelmäßig aufgerufen wird um die ListView zu aktualisieren) aus der BlockingCollection eine sortierte Liste mache und diese dann als Basis für die Datenanzeige nimmt. Alles andere war mir zu kompliziert, trotzdem danke für die Infos 😕
@witte das ist glaub ich die gleiche Extension Method, die auch BlockingCollection hat, dementsprechend hätte ich hier das gleiche Problem.

sth_Weird

07.04.2014 - 09:59 Uhr

Halli hallo,

ich versuche mich gerade daran, eine BlockingCollection zu sortieren. Wenn ich OrderBy verwende, bekomme ich die sortierte Liste als Rückgabewert, ich möchte aber die Original-Liste sortiert haben.
Hintergrund: Ich habe verschiedene Threads/Tasks, die Datenverkehr auswerten, und fertige "Pakete" in Form von Events an meine "Paket-Sammelklasse" schicken. Diese Pakete sollen dann zeitlich in aufsteigender Reihenfolge in einer Liste stehen (aufgrund der Threads/Events habe ich hierfür eine BlockingCollection genommen). In welcher Reihenfolge die Events ankommen steht ja nicht fest, deshalb muss man die Liste nach Anfügen eines Pakets neu sortieren (das neue Paket könnte ja "älter" sein als die bisher empfangenen).
Die Liste wird dann in einer ListView angezeigt, aufgrund der evtl großen Menge an Daten ist die Datenquelle der ListView aber virtual. Sonst könnte ich ja einfach die Datenquelle setzen als meineListe.OrderBy(...).
Muss ich die BlockingCollection zum Sortieren komplett neu setzen (also quasi eine temporäre Liste erstellen aus meineListe.OrderBy(...) und aus dieser wieder eine neue BlockingCollection erstellen?).
Andere Ideen?

Gruß & thx
sth_Weird

08.01.2013 - 08:57 Uhr

Hallo,

ich würde gerne mal interessehalber versuchen ein Word Add-In zu erstellen, leider habe ich zu Hause nur Visual Studio Express. Den Office FAQ habe ich gelesen und auch diverse andere Seiten, überall lese ich nur, dass man für VSTO die Professional braucht.
Ich bin noch über ein Add-In-Express Tool beim googeln gestoßen, das scheint aber kostenpflichtig zu sein. Für so ein kleines privates "Mal-kurz-reinschnuppern"-Projekt will ich aber nichts ausgeben.
Gibt es für Visual Studio Express KOSTENLOSE Alternativen zu VSTO oder Add-In-Express? Mir reicht die Word-Unterstützung (Word 2007, falls das relevant ist), Excel, Outlook etc. brauche ich garnicht.

thx
sth_Weird

Ich hoffe das ist das richtige Unterforum wusste nicht ob ich es besser in Office oder Entwicklungsumgebung stellen sollte...

01.10.2012 - 10:42 Uhr

sorry wenn ich den alten Thread nochmal rauskrame, aber ich habe gerade das gleiche Problem..
Visual Studio 2010 und .NET 4.0 falls es relevant ist.

nach den obigen Anweisungen haben ich die Quit Methode MIT eingefügtem Typecast so aufgerufen:

((Application)this.wordApp).Quit(Type.Missing, Type.Missing, Type.Missing);

Microsoft.Office.Interop.Word habe ich als using-Verweis mit drin, da ich die langen Namen im Code unübersichtlich und schwer zu lesen finde.

Die Compilerwarnung geht damit bei mir NICHT weg.
Ich kann zwar fehlerfrei compilieren und auch ausführen, aber ich will ja keine Warnings im Projekt haben (habe auch oft die Einstellung "Warnings als Fehler" aktiviert und dann ginge es nicht mehr).

Verstehe hier auch denn Sinn vom casten nicht, denn ich habe ja wordApp explizit als Application angelegt, da müsste der Compiler doch eigentlich wissen was es ist grübel.

Gibt es noch andere Lösungen? Diese Mehrdeutigkeit scheint es noch bei anderen Funktionen zu geben...

gruß & danke
sth_Weird

17.08.2012 - 12:50 Uhr

Funktioniert wunderbar, danke!

die URI habe ich so gebildet:

...new Uri(string.Format(@"pack://application:,,,/{0};component/{1}", this.plugin.GetType().Assembly, this.pluginMetadata.Icon), UriKind.Absolute)

Oder gibt es dafür schon eine schönere, vordefinierte Methode irgendwo in den vorhandenen Bibliotheken von .NET, wo man nur noch Parameter einsetzen muss und das pack://... automatisch dazugebastelt wird? Es wurde auf msdn nichts dergleichen erwähnt deshalb bin ich mal davon ausgegangen ich muss das selbst zusammenbasteln.

ansonsten sage ich mal solved.

gruß
sth_Weird

17.08.2012 - 11:40 Uhr

Hallo,
ich übe mich gerade zum ersten Mal in MEF, wobei die Frage wahrscheinlich nicht MEF spezifisch ist.
Ich habe eine Host-Anwendung gebastelt und einige Dlls mit Extensions=Plugins, jedes Plugin hat Metadaten (IPluginMetadata Interface mit den Daten PluginName, PluginDescription, PluginAuthor, PluginVersion, HasMultiInstanceSupport, PluginIcon).
Im PluginIcon schreibe ich den Pfad zu einem Icon rein, das in der Dll liegt, in welchem auch das Plugin selbst liegt (z.B. "Resources/plugin.ico").
In meinem Host habe ich nun eine Listbox, die alle Plugins mit Icon und Name auflisten soll (DataTemplate mit Image und TextBlock habe ich bereits implementiert). Nun steht aber im Icon-String jedes Plugins nur "Respources/plugin" drin. Wie komme ich nun am besten von meinem Host aus an dieses Icon aus der anderen Dll?
Diese Ideen hatte ich bereits:
--> Da ich ja ein ViewModel verwende, lade ich da das Bild direkt und übergebe dem View dann das Bild anstelle eines Pfades
--> Vielleicht gibt es eine Möglichkeit, dem relative Pfad "Resources/plugin.ico" einen String vorzustellen, damit das Laden auch so geht...falls das geht, gibt es da was vorgefertigtes? Ist das sowas wie beim Laden von Resourcen aus anderen Assemblies?
--> Ist es einfacher, wenn ich das Icon in der Plugin-Dll als Resource habe und nicht einfach als Datei?
--> Oft sieht man auch, dass bei professionellen Programmen Icons einfach so im exe Verzeichnis oder einem Unterverzeichnis liegen...es wäre ja auch noch denkbar, das Plugin-Icon einfach dorthin zu kopieren und von dort zu laden, anstelle es direkt in der Dll eingebettet zu haben

Wie würdet ihr das realisieren?

Vielen Dank schon jetzt für eure Tipps!
sth_Weird

08.08.2012 - 12:49 Uhr

Ich habe auch schon einige plugin-fähige Anwendungen entwickelt (meist mit dem IPlugin Interface Ansatz, da der einfach am leichtesten zu implementieren ist und für die Anwendungen immer gereicht hat). Die waren halt alle in Winform (wo ich mich auch zu genüge auskenne), in WPF wird ja vieles anders gehandhabt und es gibt auch viele Lösungsansätze die in Winform garnicht gehen (und einem Winform Programmierer deshalb auch garnicht einfallen), deshalb will ich einfach wissen, ob dieses generelle Vorgehen der Plugin-Entwicklung auch so in WPF "technologie-gemäß" ist.
Zu meiner jetztigen Anwendung:
Die Datenklassen liegen in einer Dll (etwa 100 Datenklassen, geschachtelt, verküpft etc.)
Die Klassen zum Lesen/Schreiben in eine Datenquelle liegen in einer Dll
Das Framework ist in einer Dll, das Framework ist eine "leere" Form, es hat nur zur Aufgabe die Plugins zu laden und deren Ansichten/Funktionalität bereitzustellen.
Das IPlugin Interface ist in einer Dll
Jedes Plugin ist in einer Dll (kein Muss in dem Sinne, eine Dll könnte auch mehrere Plugins enthalten).
Jedes Plugin kann über die Datenschnittstelle Daten lesen/schreiben und stellt eine pluginspezifische Übersicht dar. ViewModel und View sind also beide in dem Plugin angesiedelt, da sie thematisch zusammengehören (und ggf. auch wirklich das Plugin bilden, sie sollen also nicht ausgelagert werden). Ich überlege nun, wenn ich in einem Plugin einen Datentyp anzeigen will und diesen aus dem ViewHelper rausholen will, der als Schlüssel den Datentyp selbst nimmt, müsste ich ja das Objekt ins ViewModel stecken und dieses ViewModel ins View. Dann hilft mir doch eigentlich im ViewHelper weder ein Dictionary mit <Datentyp, ViewModel> noch mit <Datentyp,View>, denn ich muss ja beides wissen.
Vielleicht ist das ganze einfach zu theoretisch und ich sollte wirklich mal ein paar Zeilen dazu programmieren, um dann auch ein praktisches Beispiel liefern zu können, das hier diskutiert werden kann? Ich entwickle anfangs einfach immer am liebsten auf Papier...

gruß & danke
sth_Weird

08.08.2012 - 11:34 Uhr

Hallo,
Nach langer Zeit kann ich endlich mal wieder etwas mit WPF rumbasteln 😃
Das Ziel in Kürze:
Framework + Plugins
Die Plugins sollen u.a. Funktionalitäten, Ansichten etc. für bestimmte eigene Klassen liefern.
Soll heißen, Plugin1 weiß z.b. wie man Typ ClassA und ClassB grafisch darstellt, Plugin2 weiß wie man ClassC und ClassD grafisch darstellt. Außerdem bietet Plugin1 auch die Funktionalität, ein Objekt vom Typ ClassA etc. zu erstellen, editieren, löschen (Wizard).
Ich würde nun gerne haben, dass Plugin2, wenn dort ein Objekt von ClassA angewählt wird, auch die Sichten/Editiermöglichkeiten aus Plugin1 hat, ohne dass Plugin2 Plugin1 kennt.
Ich hoffe das ist soweit verständlich.
In Winforms habe ich ähnliches schon programmiert, aber in WPF sind die Vorgehensweisen ja oft anders.
Ich habe mir mal als WPF-praktisch-Unerfahrene einen Ansatz ausgedacht und wüsste gerne, ob das so passt:
Jedes Plugin registriert seine Ansichten für bestimmte Klassen an einer zentralen Stelle/Helperklasse
(statische? Klasse ViewHelper oder so)
Jeses Plugin registriert seine Aktionen für bestimmte Klassen an einer zentralen Stelle/Helperklasse
(statische? Klasse ActionHelper oder so).
Beide Helperklassen hätten dann ein Dictionary mit Key=Type und Value=...
Wenn nun in irgendeinem Plugin ein Objekt vom Typ X angewählt wird, guckt das Plugin z.B. im ViewHelper nach, ob dieser weiß, wie Typ X angezeigt werden soll, falls ja, verwendet es die Anzeige dort. Außerdem guckt es im ActionHelper, welche Aktionen es für diesen Typ gibt, und bietet die (in Form eines Menues, Ribbons etc.) an.
Diesen Ansatz habe ich auch so in meiner WinForm Anwendung und hat dort prima funktioniert...kann man das so für WPF übernehmen?
Ich würde gerne mit MVVM arbeiten. In einem Plugin haben ich zu einem Typ ein ViewModel und ein DataTemplate, das weiß, wie es dieses ViewModel anzeigt. Was registriere ich nun im ViewHelper, das ViewModel oder das DataTemplate?
Analog dazu, realisiere ich die Aktionen wie "Neu" "Ändern" "Löschen" eines Typs im ActionManager am besten als ICommand oder wie sonst?

gruß & danke
sth_Weird

23.05.2012 - 14:16 Uhr

hmm, da bin ich wohl über ein doofes Beispiel gestoßen, wo die exportTypes dementsprechend verwendet wurden...da hieß ist, dass man mit diesem Feld das designtechnisch fragliche XmlInclude() ersetzen könne.

hab es jetzt so gelöst, dass ich noch eine "Config"-Klasse darübergebastelt habe, und diese hat nun ein Property vom Typ AccessInfo. Dem weise ich ein SQLServerAccessInfo zu, und alles serialisiert und deserialisiert richtig und vollständig. Ich hätte gedacht hier ist das prinzip das gleiche, hier erkennt er ja auch, dass ein SQLServerAccessInfo vorliegt (wahrscheinlich wegen dem XmlInclude, das ich ja eigentlich nicht benutzen wollte, aber wenns halt nur so geht (es sei denn natürlich ich programmier mir händisch was)).
Schade, dass es nicht direkt vom AccessInfo aus tut, hätte gedacht hier sollte das Prinzip ähnlich sein.

22.05.2012 - 16:39 Uhr

hallo,

Ich habe versucht eine Helper-Klasse fuer die Serialisierung meiner Datenklassen zu erstellen.
hier die relevanten Ausschnitte aus meinen Serialize und Deserialize Funktionen:

Serialisierung:

...
XmlSerializer serializer = new XmlSerializer(objectToSerialize.GetType());
writer = new StreamWriter(fileName, false, Encoding.UTF8);
      try
      {
        serializer.Serialize(writer, objectToSerialize);
...

Deserialisierung:


public static SerializeType Deserialize<SerializeType>(string fileName) where SerializeType : class
{
...
// SerializeTyp ist die (Basis-)Klasse, deren Objekt deserialisiert werden soll
// wobei GetDerivedTypes die von der vorliegenden Klasse abgeleiteten Typen ermittelt, die in der // aktuellen Anwendung bekannt sind (funktioniert auch problemlos).
Type[] extraTypes = GetDerivedTypes(typeof(SerializeType)).ToArray(); 
      XmlSerializer serializer = new XmlSerializer(typeof(SerializeType), extraTypes);

      if (File.Exists(fileName))
      {
        fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        deserializedObject = (SerializeType)serializer.Deserialize(fileStream);

Ich dachte, so kann ich auch Dateien deserialisieren, die nicht dem SerializeType, sondern einer Ableitung davon entsprechen.
Leider funktioniert das so nicht --> Fehler im XML Dokument, xyz wurde nicht erwartet 😦

Hintergrund: ich speichere in einer XML Datei die Verbindungsinformationen zu einer Datenbank. Die Basisklasse (abstrakt) ist AccessInfo, je nachdem was für ein Datenbanktyp verwendet werden soll gibt es Ableitungen SQLServerAccessInfo, MSAccessInfo mit entsprechend anderen Properties. Ich will die Infos also einlesen als Deserialize<AccessInfo>(datei.xml), weil ich ja vorher nicht weiß, was für eine Datenbank ich habe.

Ich teste das ganze, indem ich eine Instanz von SQLServerAccessInfo erstelle und serialisiere und dann versuche, das ganze wieder einzulesen. Das Format der Datei sollte also stimmen.

PS: wenn ich eine ueberlagerte Klasse bastle mit einem Property des Typs AccessInfo, dann geht es, da ich beim AccessInfo die abgeleiteten Klassen xml-include. Warum geht es nicht, wenn ich die Instanz direkt serialisieren und deserialisieren will?

EDIT: fuer den Fall der ueberlagerten Klasse wird beim AccessInfo-Element ein type-Attribut mit dem exakten Typ miterstellt. Dieses type-Attribut fehlt bei der direkten Serialisierung meiner Klasse ohne die ueberlagerte Klasse. Vermutlich geht die Deserialisierung deshalb nicht? Bekomme ich das type irgendwie durch entsprechende Parameter in die erstellte Datei rein (falls das was bringen würde)

gruß
sth_Weird

23.03.2012 - 08:42 Uhr

habe ich auch vermutet, und deshalb den "merge" manuell durchgeführt (indem ich einfach die neuen ContextMenu-Einträge per Add an das bereits für den Typ hinterlegte ContextMenu eingefügt habe, anstelle es mit der Merge-Funktion vom ToolStripManager zu mergen).
Leider ist das Phänomen das gleiche.
Weitere Ideen???
Ich meine ich hätte jetzt noch die Lösungsidee, dass ich künstich ein ParentDbMenu-Property an mein DbContextMenuEntry ranhänge (das dann hoffentlich den richtigen Eintrag enthält), aber ich verstehe trotzdem nicht, weshalb es nicht mit den normalen Bordmitteln geht, und das verwirrt und ärgert mich. Man kanns ja auch nicht richtig debuggen 😕

gruß
sth_Weird

22.03.2012 - 12:55 Uhr

Ich habe ein seltsames Phänomen und komme nicht darauf, wo mein Denkfehler/Programmierfehler ist...

Zum Hintergrund:
-->Applikation mit Plugins zur Verwaltung von Daten (diverse eigene Datenklassen, die aus einer Datenbank gefüllt werden)
Jedes Plugin kann den Funktionsumfang der ganzen Applikation erweitern, und zwar über Contextmenues, die für bestimmte Datentypen aufgerufen werden können. Es gibt eine statische Klasse ContextMenuHelper, bei der sich die Plugins mit den ContextMenues registrieren können (ggf. führt der ContextMenuHelper auch ein Merge durch, wenn verschiedene Plugins für den gleichen Typ ContextMenues bereitstellen).
Ich habe die Klasse ContextMenuStrip abgeleitet als DbContextMenu und die Klasse ToolStripMenuItem abgeleitet als DbContextMenuEntry und diverse Properties hinzugefügt.

public class DbContextMenu<T> : ContextMenuStrip where T: IDbData...
public class DbContextMenuEntry : ToolStripMenuItem...

In jedem Plugin erstelle ich diverse DbContextMenues und fülle sie mit DbContextMenuEntry-Items.
Pseudo-Code

internal sealed class PlugInContextMenues
{
   public DbContextMenu<DataClass1> data1Menu;
   public DbContextMenu<DataClass2> data2Menu;

   initMenues()
  {
      DbContextMenuItem anExampleAction = new DbContextMenuItem();
      // ... Text und Events etc einstellen
      data1Menu.Add(anExampleAction)
      ...
  }
}

Der ContextMenuHelper (Pseudo-Code):


public static class ContextMenuHelper
{
  Dictionary<Type, DbContextMenu<IDbData>> contextMenuLookup;
   //...

  public static void Contribute(Type dataType, DbContextMenu<IDbData> menuToContribute)
  {
   // prüft, ob es schon ein Menu gibt für den Typ und merged es ggf, sonst fügt es das Menu dazu.
  }

  public static DbContextMenu<IDbData> GetContextMenu(IDbData object)
  {
     // prüft ob es ein ContextMenu für object.GetType() gibt und gibt es zurück.
     // beim debuggen wird da auch tatsächlich noch das DbContextMenu zurückgegeben, 
     // und dieses wird dann vom abfragenden Plugin angezeigt.
  }

Es funktioniert soweit alles wunderbar, die ContextMenues werden richtig angezeigt und ggf gemerged.

Wenn ich nun auf einen Eintrag klicke, dann sehe ich als Sender des Events mein DbContextMenuEntry. Ich versuche nun vergeblich, auf das beinhaltende Parent DbContextMenu zu kommen, da dort noch einige Infos stehen, die ich brauche.
Folgender Versuch, senderEntry ist ein DbContextMenuEntry (das sender-Objekt des Events):

senderEntry.Owner.ContextMenuStrip

senderEntry.Owner ist vom Typ ToolStripMenuDropDownMenu. senderEntry.Owner.ContextMenu liefert null. Ich hätte vermutet, dass einer dieser beiden Eigenschaften mir das beinhaltende DbContextMenu zurückgibt. Seltsam ist, dass das ToolStripDropDownMenu, das im Owner drin steht, meinem em DbContextMenu entspricht (also es den entsprechenden Text hat und als Items auch den DbContextMenuEntry, der das Event ausgelöst hab). Aber warum ist es nicht mehr vom Typ DbContextMenu??? Ich kann es auch nicht dahin casten.

Hat jemand eine Idee, wo mein (Denk-/)(Programmier-) Fehler liegt??? Ich irre komplett im dunkeln.

gruß & danke
sth_Weird

06.03.2012 - 12:45 Uhr

Evtl. wäre aber fast schon ein Interface für einen Filter geeigneter als ein Delegat.

hmm wie meinst du das?

Prinzipiell will ich mit der Filter-Konfiguration erreichen, dass ich meine EINE Filteroberfläche für alle möglichen Datentypen verwenden kann. Die Auswahl der filterbaren Eigenschaften ergibt sich ja aus meiner Konfiguration, und wenn in der Konfiguration für eine Eigenschaft eine Funktion hinterlegt ist, dann rufe ich die auf, bekomme eine Liste<IData> und die zeige ich dann zur Auswahl in einer Combobox an.
Wie könnte ich hier die Funktion durch ein Interface ersetzen? Oder meinst du, ich erstelle pro mögliche Funktion eine Instanz so eines Interfaces und rufe für diese eine Funktion auf, die mir die Daten zurückliefert (wäre auch ne Alternative, aber ist die wirklich praktischer oder schieße ich damit eher mit Kanonen auf Spatzen?). Oder wie hast du das gemeint?

gruß & danke
sth_Weird

16.02.2012 - 10:26 Uhr

Vielen Dank für eure Antworten!

Was den Filter betrifft, könnte ich mir gut vorstellen, dass das schon mal jemand gemacht hat.

das hab ich mir auch gedacht, aber leider bisher nichts passendes dafür gefunden (jedenfalls nicht in der Komplexität, die ich brauche), deshalb mach ich's jetzt selber 😃 Falls aber jemand doch noch was findet, kann es gern hier posten, man kann sich da ja Ideen holen.

gruß
sth_Weird

16.02.2012 - 08:53 Uhr

hallo,

Ich bastle gerade an einem "allgemeinen Filter" herum. Ich versuchs mal kurz zu erklären...
In der Filter-Konfiguration steht drin, welche Properties eines (eigenen)Typs gefiltert werden können.
Ist das Property ein int, string etc., dann soll der Anwender später einfach eine Zahl, eine Zeichenkette etc eingeben können. Ist das Property aber von einem Referenztyp (eigener Typ, aber alle Typen implementieren dasselbe Interface, ich nenne es mal IData), dann wäre es ja sinnvoll, wenn der Anwender später eine Auswahl aller möglichen Objekte bekommen würde. Falls es zur Verständlichkeit beiträgt: Diese Objekte sollen aus einer Datenbank abgerufen werden.
Meine Filterkonfiguration sollte also schemenhaft so aussehen
"Filterkonfiguration für einen Typ"
(Filter-Property, Funktion)
(Filter-Property, Funktion)
...alle Properties des Type, die gefiltert werden können
wobei die Funktion bei trivialen Typen null ist und bei Referenztypen auf eine Funktion zeigen soll, die aufgerufen werden muss, um eine Liste der möglichen Werte zu bekommen (immer List<IData>).

Das Stichwort delegate ist mir durchaus ein Begriff, ich weiß nur jetzt nicht, in welcher Form ich es benutzen soll...als reines Delegate oder in Form von Func<>? Funktionieren würde denke ich beides, aber welches ist "passender", "schöner", besserer Stil? Ich mein rein "delegate" gab es ja schon seit Anfangszeiten von C#, das Func<> ist erst neuerlich dazugekommen...ist es dann "veraltet" noch das delegate zu verwenden (so wie man schon lange ne List<T> anstelle ner ArrayList verwendet)?
um etwas Code beizusteuern, diese beiden Wege könnte ich mir für den Funktionspointer vorstellen:

delegate List<IMyInterface>LoadFilterSelection(MyType anObject)

oder

Func<MyType, List<IMyInterface>> LoadFilterSelection

Langer Text kurze Frage: Welche Variante ist besser (oder ist es einfach Geschmacksache)?

gruß & danke!
sth_Weird

29.11.2011 - 08:32 Uhr

hat sich erledigt, hab beim debuggen festgestellt, dass wenn man die Methoden eines Typs abfragen, für Properties auch eine Funktion "set_Property" dabei ist, also auch eine mit "set_DbConnection"...und die wurde null gesetzt. War also mein eigener Fehler 😕

sth_Weird

29.11.2011 - 08:10 Uhr

hallo,

ich habe mir eine Testklasse für meine Datenabfrage-Klasse geschrieben und möchte nun darin alle Methoden aufrufen mit den entsprechenden Parametern und testen, ob es prinzipiell an der Syntax der verwendeten Abfragen Schreibfehler etc. gibt.
Soviel zum Hintergrund.
Um das ganze zu vereinfachen lese ich die Funktionen der Klasse ganz einfach über Reflection aus. Alles kein Problem.
Nun erstelle ich mir in meiner Klasse eine Instanz (ich nenn sie mal "AbcDbAccess") der Datenabfrage-Klasse, diese hat ein Property "DbConnection", wo quasi die "Rohdatenbankverbindung" drinsteckt. Diese wird selbstverständlich auch gesetzt und die Verbindung geöffnet.
Wenn ich also beim debuggen der Testklasse gucke, was AbcDbAccess.DbConnection ist, dann steht dort die Instanz der Rohdatenbankverbindung drin.
Invoked wird dann so, wobei mi = MethodInfo und functionParams = object[] mit Funktionsparametern sind:


mi.Invoke(this.AbcDbAccess,  functionParams)

Wenn ich nun einen Breakpoint in der Datenbankklasse setze, dann ist die Rohdatenbankverbindung, also .DbConnection, plötzlich null. this.AbcDbAccess hat also die .DbConnection Einstellung beim Invoken irgendwie "verloren".
Ich hab schon den ganzen Code durchgeforstet, aber es steht nirgends ein Aufruf "DbConnection = null";
Kann jemand was mit dem Phänomen anfangen und wie invoke ich hier richtig?
Bin für jeden Tipp dankbar!

gruß
sth_Weird