Laden...
L
Benutzerbeschreibung

Forenbeiträge von Lector Ingesamt 862 Beiträge

30.10.2013 - 22:31 Uhr

Wäre es nicht schneller wenn man mit einer Teile-und-Herrsche-Strategie da rangehen würde?
Also ein Element in der Mitte schnappen->zu groß/klein -> Element zwischen aktueller Position und Anfang/Ende schnappen->usw.
Was ich eigendlich fragen wollte ist muss ich das alles selbst implementieren oder gibts irgendwas in Linq was mir die Sache vereinfacht und trotzdem performant ist?

SortedList möchte neben dem eigentlichen Datenwert noch einen Key haben. Soll ich da einfach den Zeitwert der Objekte übergeben? Die Wunschzeit hab ich ja zu dem Zeitpunkt noch nicht.

30.10.2013 - 22:12 Uhr

Hallo miteinander.
Da ich nach langjähriger Pause endlich mal wieder mit C# arbeite habe ich gleich eine Frage.
Ich habe einige tausend Objekte, in dem sich ein Zeit-Attribut befindet. Nun möchte ich mir gerne das Objekt rausholen, dessen Zeit-Attribut am nähesten an einem bestimmten Wert liegt.

Wie mache ich das am performantesten? Welche Datenstruktur sollte ich verwenden? Ich habe bereits an SortedList gedacht. Das Problem ist dass ich meine Objekte nicht nach Zeit sortieren sollte sondern nach Math.Abs(wunschzeit - o.Zeit).

Wie würdet ihr da vorgehen?

18.04.2011 - 13:48 Uhr

Du musst dein GeometryModel schon in einen Viewport3D packen damit es richtig dargestellt wird. Tutorials zum Viewport3D gibt es haufenweise im Internet. Da solltest du leicht fündig werden

29.03.2011 - 17:22 Uhr

Per Code an diese Elemente zu kommen ist so gut wie unmöglich und auch nicht wirklich sauber.

Am besten machst du es so ähnlich wie hier: http://bea.stollnitz.com/blog/?p=53

29.03.2011 - 15:22 Uhr

Hallo,

Ich habe eine TextBox deren Text an ein DependencyProperty gebunden ist. Da ich nur bestimmte Benutzereingaben zulassen will benutze ich die Validierung von WPF. In gewissen Szenarien muss ich die Validierung für dieses Property neu anstoßen. Dies mache ich indem ich den Wert des DependencyProperties kurz ändere und wieder rücksetze. Das funktioniert auch. Leider wird dabei aber der CaretIndex der TextBox wieder zurück auf 0 gesetzt. Das ist ganz schön nervig. Weis jemand wie ich das unterbinden könnte?

22.03.2011 - 17:53 Uhr

Das liegt daran dass WPF die Mauseingaben nur erfasst wenn du auf einem eingefärbten Bereich bist. Setzte mal die Background-Eigenschaft vom StackPanel auf Transparent. Dann solltest du die Mauseingaben erhalten.

21.03.2011 - 21:43 Uhr

Wenn du Binding hinschreibst würde ich mal stark davon ausgehen dass dann auch ein Binding erzeugt wird. Wenn du einfach nur die Resource hinzufügen möchtest mach doch einfach sowas:


        <fk:TransitionPresenter 
          Name="ContenTransiter" DataContext="{Binding Path=BreadCrumb.CurrentFolder}" 
          Transition="{StaticResource Transition}">         
          <ContentPresenter  />
          <ContentPresenter  />
        </fk:TransitionPresenter>
16.03.2011 - 10:44 Uhr

Soweit ich weis kannst du den einzelnen Array-Elementen keinen Namen geben. Was funktionieren **könnte **ist folgendes (ungetestet):


<Blabla.Resources>

<!--Hier definierst du die einzelnen Array-Elemente als objekt und gibst ihnen einen key-->
<obj x:Key="obj1">blabla</obj>
<obj x:Key="obj2">blabla</obj>
<obj x:Key="obj3">blabla</obj>


<x:Array ...>

<StaticResource ResourceKey="obj1"/>
<StaticResource ResourceKey="obj2"/>
<StaticResource ResourceKey="obj3"/>

</x:Array>


</Blabla.Resources>

So solltest du auf die Objekte sowohl als Array als auch einzeln per ResourcenVerweis erreichen. Das ganze ich aber wie gesagt nicht getestet.

16.03.2011 - 09:41 Uhr

Hallo,

Ich möchte für Texteingaben ein Validierungstemplate schreiben dass so ähnlich aussieht wie die Ordnernamen-Validierung von Windows (siehe Anhang). Den Balloon-Tip habe ich als Popup realisiert. Nun habe ich aber noch 2 Probleme:

  1. Man kann einen Popup ein PlacementTarget geben. Das Popup öffnet sich dann auch immer über diesen PlacementTarget. Allerdings verschiebt sich das Popup nicht mit wenn das PlacementTarget verschoben wird (z.B. wenn der Benutzer das Fenster verschiebt). Wie könnte man dieses Problem lösen?

  2. Ein Popup kann anscheinend nicht über einem Bildschirmrand hinausgeschoben werden. Versucht man es trotzdem landet es immer am Rand des Bildschirms auf dem (laut manueller Platzierung) die meisste Fläche zu sehen wäre.
    Kann man das irgendwie abstellen? Mir wäre lieber wenn ich bereits im Vorraus ermitteln könnte ob das Popup unterhalb der TextBox noch Platz hat. Falls es nicht mehr hinpasst würde ich den Balloon lieber über der TextBox platzieren und müsste dann auch den Pfeil beim Balloon anders ausrichten. Wie mache ich das?

15.03.2011 - 13:04 Uhr

Das liegt daran dass das StackPanel seinen Innhalt auf der Laufachse (X bei Orientation==Horizontal und umgekehrt) einfach so platziert als würde dort unendlich Platz zur Verfügung stehen.

D.h. hier konkret dass der Horizontale Scrollbalken nicht angezeigt wird da das äusserste StackPanel den ScrollViewer einfach entsprechend breit macht so dass kein Horizontales Scrollen nötig wird. Dass der ScrollViewer selbst nicht mehr ins StackPanel passt merkt das StackPanel nicht.

Ich würde dir empfehlen für deine GUI ein anderes LayoutPanel zu benutzen. DockPanel eignet sich ganz gut für wenige Elemente. Für komplexes Layout empfehle ich das Grid.

15.03.2011 - 10:07 Uhr

Mach aus dem Komma einen Punkt dann gehts.

14.03.2011 - 11:43 Uhr

Nein. Das einzige auf dass du achten solltest sind dass EventHandler wieder abgemeldet werden. Das führt immer dann zu Problemen wenn sich ein kurzlebiges Objekt (z.B. ein dynamisch erzeugtes Control) auf ein Event eines langebigen Objekts (z.B. Hauptfenster) anmeldet. Wenn solche Eventhandler nicht abgemeldet werden hält das langlebige Objekt weiterhin eine Referenz auf das kurzlebige was dazu führt dass dieses nicht aufgeräumt wird und weiterhin Code ausführt wenn das Event gefeuert wird. Die Folgen sind Speicher- und Performancelecks.

Das ist aber kein grundsätzliches Problem von dynamisch erzeugten Controls.

11.03.2011 - 13:12 Uhr

StyleSelector ist das gleiche wie ein TemplateSelector nur mit Styles statt Templates.
Den kannst du in die ListBox per ItemContainerStyleSelector einklinken. Ein StyleSelector ist hier eher angebracht als ein TemplateSelector da du nur im Style die Visibility auf Collapsed setzen kannst und dass die einfachste Möglichkeit ist dein Problem zu lösen. Natürlich kannst du auch einen TemplateSelector benutzen und beim letzten Element ein leeres Template zurückgeben.

C#-Code (in welcher Form auch immer) wirst du auf jeden Fall brauchen um dieses Problem zu lösen. Aber da du für deinen Selector sowieso eine eigene Klasse machen musst zählt das ja nicht unbedingt als CodeBehind, auch wenn ein solcher Selector wohl kaum wiederverwendbar ist.

11.03.2011 - 09:03 Uhr

Der einzige Trigger der ausserhalb eines Styles funktioniert ist der EventTrigger.

Ich würde mir für deinen Fall einen StyleSelector schreiben. Innerhalb des StyleSelectors kannst du dann prüfen ob es das letzte Element ist und dort dann einen Style zuweisen bei dem Visibility auf Collapsed gesetzt wird. Das funktioniert aber nur wenn sich die Reihenfolge deiner Items nicht ändert. Der StyleSelector wird nur aufgerufen wenn ein Item hinzugefügt wird.

Wenn dynamisch Elemente zu deiner ObsCol hinzukommen würde ich entweder ein Behavior für die Liste schreiben oder CLINQ benutzen. Mit CLINQ kannst du anhand einer ObsCol wie mit LINQ ein dynamisches ResultSet-Erstellen bei dem zu z.B. sagen kannst dass das letzte Element geskippt werden soll. Dann musst du eben deiner ListBox nicht die originale ObsCol geben sondern die gefilterte CLINQ-Liste.

09.03.2011 - 18:19 Uhr

Ich hatte mal den Fall dass meine Anwendung immer so ~0,5sec-Hänger gehabt hat. Ursache war die Aufräumroutine des GarbageCollectors der bei über 100.000 Objekten schon mal 500ms brauchen kann.

In 99,9% aller Fälle fällt soetwas aber nicht ins Gewicht.

09.03.2011 - 09:09 Uhr

Hallo Big Al,

Wenn du die VisualBrush an einen funktionierenden TextBlock gebunden hast und die Brush immer noch ein falsches Ergebnis zeigt beweist dass doch schon mal dass der Fehler nicht daran liegt dass sich der TextBlock nicht aktualisiert sondern dass die Brush nicht gezeichnet wird.

Ich habe selbst noch nicht mit WinFormHosts gearbeitet weis aber dass WPF und WinForms ihre Bildschirmbereiche so einteilen dass nur eine der beiden Technologien auf einem Bereich zeichnen kann. Wenn du also über einen WinForms-Host ein WPF-Element darstellst zieht einer der beiden den Kürzeren und wird am Bildschirm nicht aktualisiert. Da ich nicht weis ob sich deine VisualBrush und dein WinFormsControl überlappen kann ich jetzt allerdings nicht mit Sicherheit behaupten ob diese Theorie hier zutrifft.

Snoop hat bei mir übrigens auch öfters mal die Angewohnheit abzustürzen wenn die Gui-Controls zu zahlreich werden.

08.03.2011 - 10:06 Uhr

Versuch doch mal mit Snoop die Elemente genau zu analysieren um herauszufinden ob es wirklich am Binding liegt oder ob sich vielleicht nur die VisualBrush nicht neu zeichnet.

Was passiert wenn du in der VisualBrush deinen TextBlock nicht erneut anlegst sondern per {Binding ElementName=textBlockImGrid} auf den bestehenden verweist der funktioniert? Löst das dein Problem?

04.03.2011 - 10:44 Uhr

Ich habe gerade herausgefunden dass es daran liegt dass der lokale DepdendencyProperty-Wert von SelectedIndex gesetzt ist. Wenn ich vom Code aus auf die ComboBoxen zugreife und ClearValue(Selector.SelectedIndex) aufrufe aktualisiert sich der Wert. Auch wenn das keine saubere Lösung ist.

01.03.2011 - 15:03 Uhr

Nein.

Im Model befinden sich sowohl Methode als auch Daten für den Kunden.

Das ViewModel ist lediglich ein Adapter der es der GUI ermöglicht mit dem Model zu kommunizieren.

Aufgrund deiner Schlussfolgerung habe ich den Eindruck dass dein Verständnissproblem nichts mit MVVM oder WPF zu tun hat sondern dass du noch nicht viel Erfahrung mit der Objektorientierung im Allgemeinen hast. Vielleicht hilft es dir wenn du dir vorerst einmal einige Beispielprojekte dazu anschaust. MVVM ist nichts anderes als eine WPF-komforme Erweiterung des klassischen objektorientierten Architektur. Um MVVM zu verstehen musst du zuerst die Grundsätze der Objektorientierung kennen. Wenn du diese noch nicht verinnerlicht hast würde ich dir vorschlagen dir diese zuerst zu Gemüte zu führen.

01.03.2011 - 14:07 Uhr

Ich würde für diese Überlegung nicht von UserControls aus gehen sondern mir GUI-unabhängig einmal überlegen welche Objekte du in deinem Programm brauchst. Das hat an sich noch nichts mit MVVM zu tun und wird in der Objektorientierung grundsätzlich so gemacht. Wenn dein Programm z.B. die Verkaufszahlen von einem Autohaus verwalten soll würden sich Klassen wie Auto, Verkauf, Verkäufer, Kunde ... anbieten. Dies sind deine Models. Genauso würde man es auch bei einer klassische WinForms-Anwendung oder mit anderen Technologien machen.

Die besonderheit an MVVM ist nun dass du dir für jede dieser Klassen ein ViewModel strickst welches du dann in der GUI verwenden kannst. Wie deine GUI aussieht ist unabhängig von der Anzahl der Models. Wenn du z.B. in mehreren UserControls ein Objekt vom Typ Auto anzeigen möchtest brauchst du die Auto-Klasse nicht X-Mal neu erfinden.

01.03.2011 - 13:48 Uhr

Hallo Jimmy99,

Also ins Model gehört sich weder ein DataGrid, UserControl noch sonstige GUI-Elemente. Ins Model kommen lediglich die Daten die du brauchst und sämtliche Methoden die in diesem Context nützlich sind.

Dann brauchst du ein ViewModel, welches als Wrapper um das Model agiert. Dort kapselst du alle Eigenschaften via INotifyPropertyChanged und alle Methoden via Commands.

In die View kommt anschließend die GUI die ViewModels anzeigt und bearbeitet. Sie wird ausschließlich in XAML geschrieben und arbeitet per Bindings mit dem ViewModel zusammen.

Solltest du mit der Basisfunktionalität von WPF nicht auskommen und zusätzliche Funktionen (z.B. Live-Sortierung) benötigen kannst du dir entweder Behaviors schreiben und diese von deiner GUI aus verwenden oder diese Funktionalitäten mit ins ViewModel packen.

01.03.2011 - 13:01 Uhr

Hallo,

Ich habe ein kleines DatePicker-Control geschrieben mit dem man ein Datum auswählen kann. Ich weis dass es bereits einige Calendar-Controls im Internet gibt. Da ich jedoch .NET 3.5 nutze und nur eine einfache Darstellung über 3 ComboBoxen möchte habe ich selbst ein Control entworfen.

Im Control selbst sind folgende Eigenschaften als DependnecyProperties definiert:

Date (nullable DateTime)

Day
Month
Year
(sind 0 wenn Date null ist)

DayList
MonthList
YearList
(Auflistung für die ComboBox)

Im ControlTemplate definiere ich die ComboBoxen für Tag/Monat/Jahr so:


<ComboBox Name="cboDay"
SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Day,Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=DayList}"/>

Wenn Anfangs kein Datum gesetzt ist sind die ComboBoxen leer. Wird ein Tag ausgewählt steht der Wert im Control drin (alles passt). Wir aber das Datum auf null gesetzt habe ich das Problem dass sich die ComboBoxen nicht aktualisieren obwohl Day/Month/Year auf 0 gesetzt sind. Platziere ich im ControlTemplate einen TextBlock der diese Werte anzeigt (mit dem gleichen Binding wie bei der ComboBox) sehe ich auch 0. Nur bei der ComboBox scheint sich das Binding nicht zu aktualisieren. Wäre toll wenn jemand einen Lösungsansatz hierfür hätte.

18.02.2011 - 11:19 Uhr

Also wenn ich dich richtig verstanden habe benutzt eine Fremdanwendung deine Library. In dieser Fremdanwendung ist ein Bug der dazu führt dass sich die Anwendung nicht beenden lässt. Und nun möchtest du in deiner Library diesen Bug beheben.

Das lässt sich so nicht sauber lösen. Wenn sich die Anwendung nicht sauber beendet dann ist das ein Problem eben dieser Anwendung. Da kannst du in deiner Library nicht viel machen. Ich würde dir raten Kontakt mit dem Entwickler dieser Anwendung aufzunehmen damit der Fehler dort beseitigt wird wo er auftritt.

Sollte das (aus welchen Gründen auch immer) nicht möglich sein kannst du folgendes Versuchen:

Greife über Application.Current auf die Anwendung zu und versuche über diesen Weg den Shutdown-Mode zu setzen.
Oder versuche die Anwendungsassembly über den .NET-Reflektor zu analysieren. Es gibt für den Reflector ein Plug-In names Reflexil mit dem du die Assembly auch verändern kannst. Evtl. kannst du damit den Bug selbst beheben. Das ist aber alles ein Hack.

18.02.2011 - 10:14 Uhr

Vielleicht hilft es dir wenn du in deiner App.xaml den ShutDownMode so einstellst dass deine Anwendung sich mit dem Hauptfenster beendet.

09.02.2011 - 11:54 Uhr

Die Fehler sind nur pro System reproduzierbar. Je nachdem wo was am Cache kaputt ist gehen eben bestimmte Zeichen nicht. Wenn auf einem anderen System der Cache korrupt ist sind das dort aber höchstwarscheinlich ganz andere Zeichen. Auf unserem System ist die Software nur bei relativ selteten Zeichen abgestürzt. Bei anderen Systemen hatten wir das Problem dass nichteinmal unser StartScreen angezeigt wurde weil dort warscheinlich irgendein häufiges Zeichen kaputt war.

Die Ursache für den kaputten Cache kann ich leider nicht mit Sicherheit bestimmen. Laut einigen Quellem im Internet soll es daran liegen dass bestimmte Grafikkartentreiber den Chache überschreiben wenn dieser im RAM ist. Das steht auch in dem von dir genannten Link.

Auf jeden Fall sehe ich keine Möglichkeit von meiner Anwendung aus zu verhindern dass der Cache kaputt geht. Das müsste MS eigendlich selbst erkennen und gegebenenfalls korrigieren bzw. den Cache weglöschen. Stattdessen wird das Problem zum Benutzer geschoben. Um das Problem generell zu vermeiden hatte ich vor den Cache einfach gar nicht zu benutzen.

09.02.2011 - 10:57 Uhr

Wenn man ihn nicht deaktivieren kann ist das natürlich doof weil wir immer wieder solche Probleme haben werden... Normalerweise müsste WPF automatisch merken dass im FontCache irgendwas nicht stimmt und ihn dann selbst leeren.

09.02.2011 - 10:04 Uhr

Hallo Taipi88,

Das habe ich bereits gefunden. Mir geht es aber nicht darum den FontCache auf einen bestimmten PC zu löschen (das habe ich bei unserem Problem-PC bereits gemacht) sondern ihn generell in meiner Anwendung zu deaktivieren so dass es gar nicht zu solchen Problemen kommen kann.

09.02.2011 - 09:30 Uhr

Hallo liebe Community,

Ich suche eine Möglichkeit den FontCache von WPF für meine Anwendung zu deaktivieren.

Der Grund dafür ist dass sich eine WPF-Anwendung bei einem korrupten FontCache komplett aufhängt (1 Kern voll ausgelastet, GUI reagiert nicht mehr). Wir haben in letzter Zeit hin und wieder mal Bugreports bekommen bei denen sich das Fenster unserer Anwendung nicht öffnete. Stattdessen sah man nur ein schwarzes Rechteck wo das Fenster sein sollte. Die Einträge im Logfile endeten an der Stelle wo das Fenster angezeigt werden sollte. Diese Woche hatten wir das gleiche Problem an einem PC in unserer Firma. Sobald man bestimmte Fenster öffnen wollte hat sich die GUI aufgehängt. Ich habe dann solange rumprobiert bis ich rausgefunden habe dass es am Copyright-Zeichen liegt. Sobald ich dieses Zeichen aus dem Info-Fenster entfernt hatte ging es wieder. Danach habe ich herausgefunden dass sich die Anwendung auch aufhängt wenn man das Copyright-Zeichen in eine TextBox schreibt. Das ging auch mit anderen Sonderzeichen. Beim Buchstaben Ü konnte ich das reproduzieren. Ö und Ä verursachten keine Probleme.

Irgendwann habe ich dann herausgefunden dass es am WPF-Font-Cache lag. Nachdem wir diesen gelöscht hatten ging alles wieder.

Nun bin ich am überlegen wie wir zukünftig mit diesem Problem umgehen. Ich bin mir ziemlich sicher dass der FontCache das Problem für einige der Bugreports aus der Vergangenheit war. Nun würde ich dieses Problem zukünftig gerne vermeiden. Ist es irgendwie möglich den FontCache für meine Anwendung komplett zu deaktivieren so dass es gar nicht zu diesem Problem kommen kann? Hatte jemand von euch bereits einmal Probleme mit dem FontCache?

01.02.2011 - 15:18 Uhr

Habe gerade ein kleines Beispielprojekt gemacht und konnte den Fehler nicht reproduzieren. Ich habe dann in meinem Projekt nochmal genauer gedebuggt und festgestellt dass in meinem ViewModel der getter eine Exception wirft wenn der Wert noch nicht belegt ist. Ursache ist eine kleine Typumwandlung. Da ich an diesem Fehler wohl selbst Schuld war wiederrufe ich meine Theorie zur fehlerhaften Pfadauflösung von Bindings. Die funktionieren jetzt alle wunderbar auch wenn irgendwo im Binding-Path der Wert null vorkommt.

Trotzdem danke für die viele Vorschläge.

01.02.2011 - 14:11 Uhr

Hallo,

Das mit dem Priority-Binding bzw. FallbackValue ist nicht nötig da im Falle eines Null-Werts auch Null übertragen wird. Für den Fall dass kein Bild vorhanden ist zeigt mein PictureViewer eine Default-Grafik an:


<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=DisplayedPicture.Picture}" Value="{x:Null}">
   <Setter Property="Template">
        <Setter.Value>
               <!--Hier steht eine Default-Grafik drin-->
        </Setter.Value>
   </Setter>
</DataTrigger>

Auch in diesem Beispiel gilt: Sowohl DisplayedPicture als auch Picture kann null sein. Und auch hier wird ein Binding-Error erzeugt wenn DisplayedPicture null ist weil die Binding-Klasse versucht auf die Picture-Eigenschaft zuzugreifen was zu einer NullReference-Exception führt. In diesem Fall wird vom Binding dann auch der Wert null zurückgeliefert. Das führt dazu dass der DataTrigger wie gewollt ausgelöst wird udn die Default-Grafik einblendet.

Der Vorschlag von xxxprod scheint zu keiner NullReferenceException zu führen. Offenbar prüft das Binding intern ob die Bindingsquelle null ist. Wenn jedoch beim Auflösen des Binding-Paths irgendwo ein Wert null ist wird ein Binding-Error ausgelöst. Nur wie gehe ich beim oben genannten DataTrigger vor?
Im Code würde ich einfach folgendes hinschreiben:


if(DisplayedPicture != null && DisplayedPicture.Picture != null)

Durch die logische Und-Verknüpfung würde der hintere Teil nur ausgeführt werden wenn der vordere Teil passt. Ich habe mal versucht einen MultiDataTrigger zu verwenden um auf beide Bedingungen zu prüfen. Allerdings erlaubt es die Condition-Klasse nicht auf null-Werte zu prüfen. Das funktioniert nur mit einem einfachen Trigger.

Wäre toll wenn mir jemand helfen könnte. Ich habe heute gelesen dass die Binding-Errors ziemlich viel Laufzeit kosten: http://www.wpftutorial.net/10PerformanceTips.html

01.02.2011 - 11:33 Uhr

Das möchte ich ungern machen. Es gibt auch Szenarien bei denen komplexere Typen zum Einsatz kommen die ich nicht einfach auf einen Dummy-Wert setzen kann.

Es muss doch möglich sein soetwas in der GUI zu handhaben. Schließlich ist es doch völlig legal dass ein Wert einmal null sein kann.

Wenn ich ein solches Szenario im Code habe schreibe ich normalerweise if(irgendwas != null) davor. Soetwas sollte im Binding auch möglich sein...

01.02.2011 - 10:37 Uhr

Hallo,

Ich habe in meiner GUI eine ListBox, welche mehrere Objekte anzeigt, die asyncron geladen werden. Die Objekte (ViewModels) sind immer vorhandeln. Allerdings werden sie erst leicht verzögert mit Daten bestückt damit die GUI nicht blockiert.

Jedes ListBox-Element in der GUI soll nun ein Vorschaubild anzeigen. Das mache ich mit einen Binding in einem DataTemplate:


<l:PictureViewer Source={Binding Picture.Thumbnail}/>

Im Prinzip funktioniert das auch wunderbar allerdings ist die Picture-Eigenschaft meines ViewModels ganz am Anfang noch null was zu einem Binding-Error in der Studio-Ausgabe führt. Dadurch dass sehr viele Items angezeigt werden vermute ich auch dass es die Performance verschlechtert. Nachdem die Vorschau geladen wurde wird alles richtig angezeigt. Ich möchte jedoch solche Binding-Errors vermeiden:

System.Windows.Data Error: 16 : Cannot get 'Thumbnail' value (type 'ImageSource') from 'Picture' (type 'PreviewSetViewModel'). BindingExpression:Path=Picture.Thumbnail; DataItem='PictureViewer' (Name='pictureViewer'); target element is 'PictureViewer' (Name='pictureViewer'); target property is 'NoTarget' (type 'Object') TargetInvocationException:'System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.

Das ist nicht der einzige Binding-Error in meinen Programm. Ich habe bereits an mehreren Stellen solche Szenarien an denen der Binding-Pfad nicht komplett aufgelöst werden kann da irgendein Element in der Kette null ist. Wobei null durchaus ein legaler Wert ist da bei mir alles asyncron geladen wird und erst angezeigt wird wenn es da ist.

Wie kann ich solche Fehler vermeiden?

25.01.2011 - 08:22 Uhr

Sowohl RelativeSource Self als auch FindAncestor funktionieren auch nicht. Ich vermute das liegt daran dass ich mich innerhalb der CommandReaction nicht in der GUI befinde. An solchen Stellen funktionieren auch Bindings per ElementName nicht. Dieses Problem wurde hier bereits einmal beschrieben: Binding funktioniert nicht

Ich habe jetzt einen Workaround gemacht indem ich das Control innerhalb des Windows innerhalb 2er ContentControls gelegt habe mit denen ich das Window abfrage:


<UserControl ...>
    <UserControl.Resources>
        <Controls:DataContextSpy x:Key="spy"/> <!--Dieser spy überwacht den Standard-DataContext-->
    </UserControl.Resources>
    <ContentControl DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"> <!--Innerhalb dieses ContentControls wird das Window als DataContext gesetzt-->
        <ContentControl>
            <ContentControl.Resources>
                <Controls:DataContextSpy x:Key="wndSpy"/> <!--Mit diesen Spy kann ich aufs Window zugreifen. Das 2. ContentControl ist dazu da damit der Spy den DataContext vom Element darüber bekommt. Den DataContext des direkten Elements bekommt er nicht-->
            </ContentControl.Resources>
            <Grid DataContext="{Binding Source={StaticResource spy},Path=DataContext}"> <!--Hier wird wieder der originale DataContext gesetzt-->
                <Controls:UIElementBehavior.CommandReactions>
                    <Controls:CommandReactionCollection>
                        <Controls:CommandReaction TriggerCommand="{Binding Source={StaticResource spy},Path=DataContext.Register}"
                                                  CommandOnSucceeded="ApplicationCommands.Close"
                                                  CommandOnSucceededTarget="{Binding Source={StaticResource wndSpy},Path=DataContext}"/> <!--Hier können wir dann endlich über den Spy auf das Fenster zugreifen. Da wir hier ein Binding ausserhalb des VisualTrees machen klappt ein Binding nur über Resources-->
                    </Controls:CommandReactionCollection>
                </Controls:UIElementBehavior.CommandReactions>
                ..........
            </Grid>
        </ContentControl>
    </ContentControl>
</UserControl>

Bindings sind ja schon was ganz tolles aber ich würde echt gerne mal mit demjenigen reder der sich ausgedacht hat dass man nur vom VisualTree aus auf VisualElements zugreifen kann...

Wäre toll wenn jemand noch Vorschläge hat wie man das einfacher u./o. sauberer lösen könnte. Diese Version funktioniert zwar aber gefallen tut mir das gar nicht...

24.01.2011 - 08:28 Uhr

Also {TemplateBinding .} funktioniert nicht. Wenn ich das mache meckert der Compiler: Der Typ ""wurde nicht gefunden. Beachten Sie, dass bei Typnamen die Groß- und Kleinschreibung berücksichtigt wird.

Beim Binding auf das TemplatedParent kompiliert zwar allerdings kann es zur Laufzeit nicht aufgelöst werden. Ich vermute dass das TemplatedParent nur verfügbar ist wenn man sich auch in einem **Template **befindet. Was ich bräuchte wäre eine Art StyledParent.

21.01.2011 - 10:18 Uhr

Hallo,

Ich habe gerade ein kleines XAML-Problem.
Ich befinde mich im Style eines Fensters und möchte von dort aus auf dieses Fenster zugreifen. Dummerweise weis ich nicht wie ich das in XAML ausdrücken könnte.

Im Beispiel-XAML sieht man einen Hyperlink. Dieser Link öffnet ein Fenster in dem sich ein Benutzer einen Account anlegen kann. War das anlegen des Accounts erfolgreich soll sich das Fenster wieder schließen. Dazu müsste ich die Fragezeigen im Beispielcode nur noch das Fenster ersetzen, auf das sich der Style bezieht. Es wäre toll wenn jemand wüsste wie ich das an dieser Stelle hinschreibe.


<Hyperlink>
    <Hyperlink.Command>
        <Controls:ShowWindowCommand ShowWindowModal="True">
            <Controls:ShowWindowCommand.WindowStyle>
                <Style TargetType="{x:Type Window}" BasedOn="{StaticResource PopupWindow}">
                    <Setter Property="Title" Value="{DynamicResource RegisterHeaderText}"/>
                    <Setter Property="Width" Value="350"/>
                    <Setter Property="SizeToContent" Value="Height"/>
                    <Setter Property="Content" Value="{x:Static l:MySocketViewModel.Instance}"/>
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <l:Register/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Controls:WindowBehavior.CommandReactions">
                        <Setter.Value>
                            <Controls:CommandReactionCollection>
                                <Controls:CommandReaction TriggerCommand="{Binding Source={x:Static l:MySocketViewModel.Instance},Path=Register}"
                                                          CommandOnSucceeded="ApplicationCommands.Close"
														  CommandOnSucceededTarget="???????"/><!--Hier soll das Fenster hin auf das sich der Style bezieht-->
                            </Controls:CommandReactionCollection>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Controls:ShowWindowCommand.WindowStyle>
        </Controls:ShowWindowCommand>
    </Hyperlink.Command>
    <TextBlock Text="Blablub"/>
</Hyperlink>

20.01.2011 - 15:18 Uhr

Achso. Ich dachte der Mauszeiger soll als eine Art 'Guckloch' dienen und das Overlay immer an einer kreisförmigen Stelle transparent machen.

Wenn ich dich jetzt richtig verstanden habe möchtest du dass die bereits freien Guck-Löcher nicht wieder verschwinden sondern bleiben. Und wenn der Benutzer an einer anderen Stelle mit der Maus 'malt' wird das Hintergrundbild an dieser Stelle auch 'freigerubbelt'.

Da fallen mir folgende Möglichkeiten ein:

  1. Du Stellst dein Bild nicht per Image dar sondern als Pfad mittels ImageBrush. Die Geometrie des Pfades ist am Anfang leer und wenn der Benutzer mit der Maus darüberzieht fügst du in die Pfad-Geometrie an der entsprechender Stelle Ellipse-Geometries ein. Diese Geometrien kannst du ja per Union()-Funktion verknüpfen.

  2. Du legst ein leere Writable-Bitmap als Opacity-Mask auf dein Image-Control und beschreibst die entsprechenden Stellen dieser Bitmaps mit volltransparenten Farben wenn der Benutzer mit der Maus darüberzieht.

Ich würde mich an deiner Stelle mal an der Variante 1 versuchen. Bei beiden Methoden kannst du natürlich auch den Over-Lay ansatz verfolgen wenn du die invertierte Opacity-Mask verwendest. Ich würde es jedoch ohne Overlay machen da es einfacher ist ein Bild direkt einzublenden als ein Overlay darüberzublenden, welches dann wiederum ausgeblendet wird.

20.01.2011 - 14:37 Uhr

Hallo Nati,

Ich würde an deiner Stelle die OpacityMask mit einer RadialGradient-Brush benutzen. Damit kannst du dann dein Overlay an einer kreisförmigen Stelle ausschneiden bzw. ausfaden.
Noch einfacher gehts übrigens wenn du das Overlay ganz weg lässt und die Opacity-Mask nur auf das Bild selbst anwendest so dass nur der Bildbereich angezeigt wird der in der Overlay-Variante ausgeblendet werden sollte.

10.01.2011 - 11:34 Uhr

Hallo dewebey,

Benutze doch einfach für den Bereich ein Content-Control welches du je nach Zustand mit dem Login-Control bzw. einem Control zum Anzeigen des Benutzernamens füllst.
Zum befüllen dieses ContentControls kannst du ja einen Trigger verwenden.

15.12.2010 - 15:24 Uhr

Das IsFocused-Flag steht immer auf false.
Eine gobale Liste aus Fenstern möchte ich nicht machen da ich an JEDER Stelle wo ein modales Fenster auf- und zugeht Code einfügen muss der nur dieser Drag'n-Drop-Aktion dient.
Application.Current.Windows kann ich auch nicht verwenden da dort keine nativen OpenFileDialoge drin stehen sondern nur WPF-Fenster.

15.12.2010 - 14:47 Uhr

Hallo,

In habe eine WPF-Anwendung mit einem Hauptfenster. Der Benutzer kann verschiedene modale Dialoge öffnen um div. Sachen einzustellen. Ausserdem kann der Benutzer vom Windows-Explorer aus Dateien in das Hauptfenster ziehen. Das funktioniert soweit wunderbar.

Nun habe ich allerdings festgestellt dass diese Drag'n-Drop-Aktionen auch funktionieren wenn ein modales Fenster geöffnet ist was ich unterbinden möchte. Wie mache ich das?

Ich habe schon versucht Activate() aufzurufen und IsActivated abzufragen. Allerdings sind diese Werte auch auf true wenn ein modales Fenster geöffnet ist. Ich habe auch schon versucht IsMouseOver abzufragen. Dieses Flag ist auf false wenn ein modales Fenster geöffnet ist, scheint aber hin und wieder auch auf false zu sein wenn es funktionieren sollte.

Kennt jemand eine zuverlässige Methode um abzufragen ob gerade modale Fenster geöffnet sind? Native Non-WPF-OpenFileDialogs sollten auch erkannt werden.

07.12.2010 - 18:09 Uhr

Hallo,

Ich habe ein WPF-Programm mit einem Dokumentenmanagement ähnlich wie Word oder Excel. D.h. der Benutzer kann ein Dokument neu anlegen, speichern, öffnen, drucken, schließen, etc. Wenn ein ungespeichertes Dokument geschlossen werden soll gibt es natürlich eine Sicherheitsabfrage. Beispielszenarien dafür sind z.B. wenn der Benutzer das Programm schließen will, ein neues Dokument anlegt oder ein altes öffnet. In diesen Fällen hat der Benutzer die Möglichkeit auf 'Speichern', 'Verwerfen', oder 'Abbrechen' zu drücken. Alle dieser Dokumentenfunktionen sind asyncron.

Meine Frage ist nun: Kann man ein solch komplexes Szenario mittels MVVM und Commands überhaupt lösen? Die oben beschriebene Logik habe ich bereits vor längerer Zeit im Code-Behind implementiert und es funktioniert auch. Allerdings finde ich diesen Ansatz äusserst unschön da ich alles andere auch immer ganz MVVM-like mit ViewModels, Commands und Bindings gelöst habe. Allerdings weis ich beim besten Willen nicht wie ich dieses Szenario mit MVVM lösen könnte da irgendwie jede Funktionalität von einer anderen abhängt und alles asyncron ist.

Ich würde mich freuen wenn sich vielleicht jemand melden würde der ein solches Standard-Dokumentenmanagement wie in Word schon einmal selbst mittels MVVM entwickelt hat oder eine Idee hat wie man soetwas vernünftig lösen könnte.

01.12.2010 - 10:34 Uhr

Kannst du dein Problem noch etwas genauer beschreiben? Du hast geschrieben dass die Übergänge zwischen Ellipse und Dreiecken nicht richtig dargestellt werden. Dein Screenshot sieht jedoch nicht so aus als würde ein Übergang nicht richtig dargestellt werden.
Oder wolltest du sagen dass die Animation ruckelt? In diesem Fall kannst du per Timeline.SetDesiredFramerate die Framerate auf 30fps beschränken. Das wirkt manchmal Wunder. Default-Framerate ist 60fps.

30.11.2010 - 14:37 Uhr

Setze einfach folgende Werte des Grids:

HorizontalAlignment = Stretch (Defaultwert)
VerticalAlignment = Center
MinHeight = Höhe des Grids

25.11.2010 - 18:06 Uhr

            <Canvas Background="Transparent">
                <Canvas.Style>
                    <Style TargetType="Canvas">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Background" Value="Red" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Canvas.Style>
            </Canvas>

Den Canvas bekommt nur Mauseingaben wenn der Background ungleich null ist. So sollte es funktionieren.

25.11.2010 - 17:20 Uhr

Das man dem Popup kein Template zuordnen kann ist natürlich schade.

Ich habe allerdings eine weitere Idee: Du gestaltest einen ItemContainerStyle-Selektor um den 1. Element der Auflistung einen anderen Style zuzuweisen. Dieser Style setzt ein anderes Template in dem die Header-Zeilen eingeblendet werden. Dabei ist darauf zu achten dass die Header-Zeile am oberen, linken und rechten Rand bündig anstößt damit man den Mouse-Over-Effekt des ComboBoxItems nicht auf der Header-Zeile sieht. Ausserdem müsste man irgendwie verhindern dass die Header-Zeile in der ComboBox direkt sieht wenn das erste Element ausgewählt ist.

Wenn das zu kompliziert ist lässt sich der Ansatz mit dem Popup-Style vielleicht weiter verfolgen indem du im Style ein Behavior aktiviert welches irgendwie den Header einblenden kann. Wie dieses Behavior genau funktioniert kann ich dir auf Anhieb leider nicht sagen aber auf diese Weise hast du wesentlich mehr Möglichkeiten in den Ablauf einzugreifen als via XAML.

Zur Not kannst du auch beim Popup einfach als Background eine Visual-Brush setzen welche die Header einblendet. Damit diese nicht von den Elementen überdeckt werden kannst du evtl. die Padding-Eigenschaft des Popups setzen.

Da ich in meiner Anwendung für alle Elemente einen eigenen Style schreibe habe ich solch ein Problem noch nie gehabt. Ich hoffe dich bringt einer der Ansätze weiter.

25.11.2010 - 15:11 Uhr

Meine Lösung funktioniert auch ohne das komplette 'Windows-abhägige' Template zu überschreiben. Dazu gibt es einen kleinen Trick:

Du fügst in die Resource-Section der ComboBox einfach einen Style ein der automatisch auf alle Popups angewendet wird. Dieser 'injected Style' manipuliert dann das Popup so dass dort Header eingeblendet werden. Alles ausserhalb des Popups (also die normale ComboBox) bleibt unbeeinflusst. 😉

Durch ein ItemTemplate der ComboBox manipulierst du die Items so dass die Daten unter die Header geschrieben werden.

25.11.2010 - 14:17 Uhr

Mit dem Control-Template tauschst du tatsächlich das komplette Aussehen des Controls aus. In diesem Aussehen ist auch definiert dass eine ComboBox ein Popup hat, welches angezeigt wird wenn sie geöffnet ist. Im Popup liegt dann ein ItemsPresenter, welcher wiederum die ganzen ComboBoxItems anzeigt.

Dieses Aussehen kann man dann natürlich so verändern dass statt des ItemsPresenters einfach eine ListView angezeigt wird. An dieser Stelle fällt mir allerdings gerade ein dass dann die Selektierung nicht mehr funktioniert da ja keine ComboBoxItems angezeigt werden.

Machs am besten so dass du im Template keine 'wirkliche' ListView benutzt sondern nur die GUI dort so gestaltest als wäre es eine ListView. Die ComboBox-Items kannst du dann per DataTemplate und/oder ItemContainerStyle so umbauen dass sie wie ListViewItems aussehen. Damit sollte die Selektierung funktionieren. Allerdings kann man die ListBoxHeader nicht größer/kleiner ziehen weil es ja keine richtige ListBox ist.

An dieser Stelle würde ich mir mal überlegen welche Features du wirklich brauchst und welchen Aufwand sie dir Wert sind. Das ganze ListView-Sortierungsverfahren musst du dir dann evtl. mit Behaviors basteln wenn du es wirklich brauchst.

25.11.2010 - 13:53 Uhr

Ich würde nicht soweit gehen die ListView in das ItemsPanel zu integrieren. Ich würde die ListView (sofern sie erwünscht ist) ins ControlTemplate packen und diese dann an die ComboBox-Items-Eigenschaft binden.

Natürlich kann man die ListView auch komplett wegrationalisieren und einfache ItemTemplates benutzen.

25.11.2010 - 12:10 Uhr

Die Werte musst du wohl oder übel per Reflection auslesen. Den Rest kannst du alles mit Templates lösen. Schau dir mal das Default-Template der ComboBox an. Dort siehst du wie das mit dem Popup geht. Eine ListView zu erstellen sollte dann kein Problem mehr sein.

23.11.2010 - 16:49 Uhr

Angenommen du hast eine Bitmap mit einer Größe von 100x100 Pixel.
Wenn du nun ein Image-Control mit dieser Bitmap anzeigst dann ist diese nicht 100 Pixel breit sondern 100 * (1/96 * dpi). Den eingeklammerten Wert kannst du auslesen.
Wenn du nun also ein WPF-Control so platzieren willst dass es genau über der Bitmap liegt musst du vorher die Bitmap-Größe auf WPF-Einheiten umrechnen und diese dann hernehmen um deine Box zu platzieren.

Das ist zugegeben etwas umständlich allerdings ergibt es durchaus Sinn dass WPF nicht mehr mit Pixeln sondern mit 'Geräteunabhängigen Einheiten' arbeitet. Wenn du auf diese Weise mit Bitmaps arbeitest musst du dafür allerdings ein klein wenig Mehraufwand tragen.