Laden...
Avatar #avatar-3262.jpg
LuckyGeorge myCSharp.de - Member
Softwareentwickler Dabei seit 17.12.2008
Benutzerbeschreibung

Forenbeiträge von LuckyGeorge Ingesamt 72 Beiträge

12.01.2012 - 18:00 Uhr

Ok, war Murks und die CollectionsViews haben das Problem erschlagen. Kam nach dem Absenden des Beitrags auch drauf ...

12.01.2012 - 17:21 Uhr

Die Suche mit dem mir einfallenden Schlagworten hat leider kein Ergebniss gebracht.

Ich habe folgendes Problem:

Eine ListBox ist in einer MVVM Applikation an eine **ObservableCollection **gebunden.


<ListBox x:Name="notificationList"
              ItemsSource="{Binding NotificationMessages}"
              SelectedItem="{Binding SelectedNotificationMessage}"
              Visibility="Collapsed"/>

Die ListBox ist deshalb unsichtbar, da ich an anderer Stelle via **ElementBinding **nur das **SelectedItem **Anzeige.

Nun möchte ich mittels zweier Buttons durch diese ListBox iterieren, also jeweils das vorherige oder eben nächste Element als neues **SelectedItem **setzen. Im ViewModel habe ich keinen Zugriff auf die Information, welches nun der nächste oder vorherige Index ist. Im Code Behind des Views möchte ich es nur ungern machen.
Ich könnte natürlich den Buttons als **CommandParameter **die ListBox mitgeben aber das entspricht nicht ganz meiner Vorstellung von MVVM.

Wie kann ich - idealerweise im puren XAML Code des Views - eine solche Iteration bewerkstelligen?

22.07.2011 - 14:55 Uhr

@Kanalpiroge: Eigentlich solltest Du die Exception sehen - zumindest in der Konsole. Ob sie den Programmfluß unterbricht hängt natürlich von den Debugger Einstellungen und deinen try ... catch Blöcken ab.

Ich habe damals das Problem nur "umgangen" indem ich alle Primary Keys auf Guid umstellte und die ID dann vor dem speichern mit Guid.NewGuid() gesetzt habe, mich also nicht mehr auf die Datenbank verlassen habe.

Später habe ich dann alles auf generische Repositories umgestellt und die ID im generischen Repository innerhalb der Add Methode neu gesetzt.

Wenn Du diesen Weg nicht gehen willst oder kannst kommst Du nicht umhin nach jedem Hinzufügen die Änderungen in der Datenbank zu persistieren - die ID wird ja erst dann von der DB erzeugt.

22.07.2011 - 14:26 Uhr

Zum einen ist der Vorschlag von Abt sehr gut - nimm das Repository Pattern.

Zum anderen: Bist Du Dir sicher das da nicht irgendwo versteckt eine Exception fliegt? Ich hatte mal beim Adden von Objekten zur EntityCollection ein ähnliches Problem. Da lag es jedoch daran, daß ich den Primary Key von der Datenbank berechnen lassen wollte so daß dieser beim adden immer 0 war - dann kann man natürlich nur ein Element hinzufügen da es sonst eine DuplicateKey Exception gibt.

Dein Codeschnippsel deutet darauf hin, daß Du ähnliches versuchst.

16.06.2011 - 17:14 Uhr

Wir haben hier aktuell eine Silverlight Applikation mit dem WCF Ria Template erstellt. Das klappt intern soweit auch ganz gut, aber nun haben wir Probleme mit dem externen Zugriff und ich habe im Moment zwar eine Ahnung aber keinen richtigen Weg wie das Problem zu lösen ist.

Folgendes Szenario:

  1. Webserver mit IIS im Intranet auf dem die SL Applikation und der Domainservice gehostet wird.

  2. Secure Gateway von Juniper (SA 2500) mit Token Authentifizierung. Dieser setzt die HTTP Aufrufe auf den internen Server um.

Greife ich von intern auf den Webserver zu klappt soweit alles, die SL App wird heruntergeladen und alle Aufrufe an den DomainService klappen.

Greife ich von extern via Gateway auf den Server zu so lande ich zunächst bei der Authentifizierung, gebe meine Credentials ein und lande dann auf dem Webserver. Der Browser lädt sich die SL App, aber wenn ich nun versuche Aufrufe an den Service zu machen bekomme ich die Exception [net_cookie_parse_header]. Ich habe mir mit fiddler2 nun mal die HTTP Aufrufe angeschaut und festgestellt, daß die Zugriffe auf den Service vom Gateway mit einer Authentifizierungsseite beantwortet werden. Der Gateway ist also der Meinung, das die SL App ein neuer "Browser" ist, welcher sich noch nicht identifiziert hat. Diese Antwort versteht die SL App natürlich nicht.

Und nun bin ich am Rätseln wie ich das Problem lösen kann und habe da ein oder zwei Ideen.

  1. Irgendwie aus dem Browser die Authentifizierung abgreifen und an die SL App übergeben. Geht sowas überhaupt?

  2. Statt sich im Browser am Gateway anzumelden direkt in der SL App authentifizieren und die Werte via Webclient an den Gateway übergeben - aber habe ich dann nicht das gleiche Problem da der WebClient und der Zugriff auf den DomainService nicht im gleichen Context stattfinden?

Und da dies ja quasi nur der Anfang aller möglichen Probleme ist wäre es bei der Architektur nicht sogar sinnvoller den Silverlight Kram beiseite zu lassen und gleich eine ASP Anwendung zu schreiben?

Für jegliche Hinweise und/oder Erfahrungen wäre ich dankbar.

27.04.2011 - 15:39 Uhr

Ich habs grad rausgefunden aber Ihr ward gerade 1 Minute schneller - ja, das DataContext Keyword hatte gefehlt. Mit:


SelectedItem="{Binding Path=DataContext.SelectedTroubleTicket, RelativeSource={RelativeSource AncestorType=Controls:SnappingGridItem}, Mode=Default}">

Hats geklappt - vielen Dank.

27.04.2011 - 14:28 Uhr

Hallo,

cih hätte da ein kleines Problem das mich jetzt schon 2 Stunden beschäftigt und ich weiss net weiter. Ich habe ein TabControl, welches an eine ObservableCollection gebunden ist. Das TabControl hat ein ContentTemplate in dem ein ListView sitzt:


	<TabControl Grid.Column="1"
	            Grid.RowSpan="4"
	            ItemsSource="{Binding Path=TroubleTicketFolders}"
	            ItemContainerStyle="{StaticResource ItemContainerStyle}"
                SelectedItem="{Binding Path=SelectedTroubleTicketFolder}"
	            TabStripPlacement="Left">
		<TabControl.ContentTemplate>
			<DataTemplate>
                <ListView ItemsSource="{Binding Path=TroubleTickets}"
				          SelectedItem="{Binding Path=SelectedTroubleTicket}">
                    <ListView.View>
                        <GridView>
....

In meinem ViewModel gibt es die Properties:


public AsyncObservableCollection<TroubleTicketFolder> TroubleTicketFolders ...

public AsyncObservableCollection<TroubleTicket> TroubleTickets ....

public TroubleTicket SelectedTroubleTicket ....

public TroubleTicketFolder SelectedTroubleTicketFolder ....

Die Darstellung als auch das auswählen eines TabItems (in dem Falle eines TroubleTicketFolder Objekts) klappt einwandfrei. Auch werden im Listview meine Objekte richtig dargestellt - aber das Binding auf ListView.SelectedItem funktioniert überhaupt nicht. Hier bekomme ich in der Console den Hinweis, daß der DataContext des ListViews der gleiche ist, den auch das TabControl verwendet (Typ: TroubleTicketFolder) und er demenstprechend natürlich meine Property im ViewModel nicht findet. Wie bringe ich ihn dazu im ListView als DataContext wieder mein ViewModel zu nehmen anstatt die Property an die das TabControl gebunden ist?

Ich hab schon versucht mit RelativeSource wieder eine Ebene höher zu springen - also auf den View selbst. Aber dann kommt logischerweise, daß mein View diese Property auch nicht hat - die ist ja im ViewModel.

PS: Die Suche nach DataTemplate und DataContext hat nichts sinnvoles gebracht obwohl mir das Problem nicht so exotisch erscheint als das es nicht vielleicht schon mal da gewesen wäre.

21.04.2011 - 16:39 Uhr

Ersetz mal die TriangleIndizes durch folgendes:


TriangleIndices="0 1 5 0 5 4 1 5 6 1 6 2 2 7 3 2 6 7 3 0 4 3 4 7 0 2 1 0 3 2 4 6 5 4 7 6"

Habs jetzt in der Rotation noch nicht überprüft aber das sollte passen. Die Indizes habe ich übrigens von dem Projekt welches hier verlinkt ist:

WPF 3D Perfomance

Warum ist die Reihenfolge der TriangleIndizes wichtig? Die Reihenfolge der Indizes gibt an, wie das Objekt zu rendern ist. Grundsätzlich gilt, wenn ich von vorn auf das jeweilige zu definierende Dreieck schaue müssen die Indizes entgegen dem Uhrzeigensinn definiert werden. Mache ich es andersrum dann definiere ich damit die Rückseite des Dreiecks. Wenn ich jedoch eine Rückseite definiere ohne eine Vorderseite definiert zu haben dann wird mir das Dreieck nicht angezeigt und ich bekomme genau den Effekt den Du beobachtet hast - der Würfel sieht ziemlich zerpflückt aus, da manche Dreieke mit ihrer Vorderseite, manche jedoch mit ihrer Rückseite definiert wurden.

Einfaches Beispiel- ich will eine Fläche mit Vorder- und Rückseite definieren. Diese Fläche besteht defacto aus 4 Dreiecken - zwei für vorne und zwei für hinten. Wenn die Punkte dieser Fläche wie folgt sind:

(0,0,0) - (1,0,0) - (1,1,0) - (0,1,0)

dann ergeben sich folgende Indizes:

  1. Dreieck vorn unten rechts:
    0 1 2

  2. Dreieck vorn oben links:
    0 2 3

  3. Dreieck hinten unten rechts:
    1 0 2

  4. Dreieck hinten oben links:
    0 3 2

Am besten ist, man zeichnet sich das auf, dann kann man einfach durch abzählen auf die richtigen Indizes kommen. Und noch einfacher wäre es einen Generator für solche 3D Primitiven zu verwenden. Charles Petzold hat einen und auch im FluidKit ist einer drin.

16.03.2010 - 11:23 Uhr

Setze mal die maxBufferSize auf mindestens die gleiche Größe wie die maxReceivedMessageSize. Das allein dürfte aber noch nicht reichen. Ich weiss nicht genau wie Du deine Bilder überträgst, aber ich vermute daraus wird ein Byte Array. Also musst Du die maxArrayLength auch hochsetzen - das hatte ich mal vergessen und mir dann nen Wolf gesucht da keine Exception fliegt.

Hier noch ein kleiner Blogeintrag zum Thema:
WCF maxStringContentLength, maxBufferSize, and MaxReceivedMessageSize

05.02.2010 - 10:15 Uhr

Zum einen Finde ich nur Installer, die ~2,5 MB groß sind, bei denen man den Rest runterläd und noch einen Download mit 231 MB, der auch nochmal 65MB downloaden möchte.

Letzteres ist das komplette Paket aber ohne das German Language Pack. Mit einem Trick kann man das ganze doch noch installieren:

  1. Setup starten.
  2. Setup weitermachen lassen bis der Dialog mit den Lizenzvereinbarungen kommt.
  3. Nun auf der HD den Setupordner suchen (ist eine GUID im Stammverzeichniss und der erste Unterordner heisst "wcu").
  4. Den Inhalt des kompletten Ordner kopieren denn man muss das Setup abrechen und dabei wird der Ordner wieder gelöscht.
  5. In die Console wechseln, in das Verzeichniss mit der Setup Exe wechseln und dort aufrufen "dotNetFx35setup.exe /LANG:ENU"

Damit habe ich gerade am Montag 5 offline Rechner auf den neuesten Stand gebracht.

Hier nochmal der Link zum 3.5 SP1 Paket: dotnetfx35.exe

*EDIT*
Die dotNetFx35setup.exe findet sich bei mir nach dem Aufruf des Installers unter:

C:\2dbd3a23eeda82536b21c742cf8a\wcu\dotNetFramework\

Je nach Plattenplatz kann es bei Dir natürlich auf einem anderen Laufwerk sein.
Ich habe mir einfach das komplette Unterverzeichniss auf einen USB Stick kopiert und eine Batch Datei geschrieben ("dotNetFx35setup.exe /LANG:ENU"). Damit hatte ich immer die komplette Offline Installation auf dem Stick.
*EDIT*

04.02.2010 - 16:16 Uhr

Sorry, hatte gestern und heute Mamutbesprechungen und habe die Antwort jetzt erst gesehen.
Grundsätzlich gilt, was fz7090 schon sagte - leider kein geschlossener Kreis. Der Grund liegt in der von Dir verwendeten Kreisformel welche sich nur bedingt auf diskrete Darstellungen übertragen lässt. Es gibt einen Weg ohne Quadrat und Wurzel .... der aber so (mit Absicht) nicht gefordert ist, also keine Angst.

Grundsätzlich bist Du schon auf dem richtigen Weg, da Du die Spiegelung an den Achsen beachtet und damit nicht den rein naiven Ansatz gewählt hast. Nun noch die Lücken schliessen und Du hast es. 😉

28.01.2010 - 15:09 Uhr

@dr4g0n76:

Bitte, Bitte, Bitte implementiere den Weichzeichner - bzw. jeden linearen und linear separierbaren Filter - nicht so. Wenn es wirklich eine LowLevelGraphics Library werden soll optimiere die Filterfunktionen. Auch wenn der Code so lesbarer ist - bei so einer Schleifen Konstruktion ist die Rechengeschwindigkeit ob der vielen unnötigen Berechnungen ein graus. Zudem skaliert diese Implementierung nicht linear sondern quadratisch zur Filtergröße.
Ich lasse Dir gerne mal eine optimierte Variante eines Mittelwertfilters mit beliebiger Filtergröße zukommen.

Dein Neighbour Konzept ist gut fürs Patternmatching - aber wenn Du deine Filter damit realisierst werden sich spätere Anwender nicht freuen. In der Bildverarbeitung muss man einfach jede Filterfunktion einzeln optimiert implementieren und kann eher selten einen generischen Ansatz wählen. Es sei denn Geschwindigkeit ist nicht relevant ...

PS: Ich werde deine PM erst heute abend beantworten können - muß dazu nochmal was nachlesen.

27.01.2010 - 09:25 Uhr

@JAck30lena: Hmm, ich finde in diesem Thread mindestens 3 Lösungen die dieser Vorgabe nicht entsprechen und so aufwendig ist die Implementierung auch nicht.

Aber gut, dann die etwas weniger spassige Aufgabe:
Das Programm muss einen Kreis "zeichnen" können durch Eingabe des Radius. Als Zeichenfeld soll ein einfaches 2 Dimensionales boolsches Array verwendet werden bei dem der Hintergrund false und der Kreis selbst true ist. Der Mittelpunkt des Kreises ist immer der Mittelpunkt des Arrays.
Die Implementierung darf nicht den naiven Ansatz verwenden, dh. einfach nur die Berechnung der Koordinaten durch:

x = Rcos(alpha) und y = Rsin(alpha)

ist nicht ausreichend. Ich schätze, daß die Implementierung in 50 Zeilen mit Eingabe möglich ist da der eigentliche Algorithmus ca. 20 Zeilen umfasst.

27.01.2010 - 08:55 Uhr

Ok, dann mal weg von den reinen Algorithmen.

Ich hätte gern die Implementierung des Marienbad Spieles mit einem Computergegner. Als Darstellung reicht die Anzahl der Hölzer als Zahl der jeweiligen Reihe. Die Ausgangsposition sieht also so aus:

1
3
5
7

Der Computergegner soll, wenn es möglich ist, die optimale Strategie fahren. Optional kann auch noch berechnet werden ob für die jeweilige Spielsituation des Computergegners eine Gewinnstrategie existiert. Einen Hinweis dazu, wie das gehen kann findet ihr hier:

http://www-i1.informatik.rwth-aachen.de/~algorithmus/algo14.php

Die Aufgabe ist ein wenig umfangreicher als ein reiner Algorithmus aber die meiste Arbeit bezieht sich eigentlich auf die Eingabe. Falls eine solche Aufgabe den Rahmen des Threads sprengt - ich hätte auch noch eine etwas kleinere.

26.01.2010 - 20:18 Uhr

Ok, wer lesen kann ist klar im Vorteil. Nun aber:


        private static void ExtendedEuclidianIterative(int a, int b, out int ggT, out int x, out int y)
        {
            x = 0;
            y = 1;
            int dX = 1, dY = 0;

            while(b != 0)
            {
                int divRem;
                int divQuot = Math.DivRem(a, b, out divRem);
                int temp = b;
                b = divRem;
                a = temp;

                temp = x;
                x = dX - divQuot * x;
                dX = temp;

                temp = y;
                y = dY - divQuot*y;
                dY = temp;
            }

            ggT = a;
            x = dX;
            y = dY;
        }

PS: Stammt natürlich nicht von mir sondern aus der Wiki. Nur was soll man bei solchen Algorithmen denn machen ....

26.01.2010 - 19:23 Uhr

Vielleicht nicht die schönste Implementierung aber das sollte es eigentlich sein:


static void Main()
{
	bool parseOk = false;
	int a=0, b=0;
	while (!parseOk)
	{
		Console.WriteLine("Integer Wert a: ";);
		parseOk = Int32.TryParse(Console.ReadLine(), out a);
	}
	parseOk = false;
	while (!parseOk)
	{
		Console.WriteLine("Integer Wert b: ";);
		parseOk = Int32.TryParse(Console.ReadLine(), out b);
	}

	int ggT, x, y;

	if (a > b)
	{
		ExtendedEuclidian(a, b, out ggT, out x, out y);
		Console.WriteLine(a + " * " + x + " + " + b + " * " + y + " = " + ggT);
		Console.WriteLine(a * x + b * y == ggT ? "Stimmt!" : "Stimmt net!";);
	}
	else
	{
		ExtendedEuclidian(b, a, out ggT, out x, out y);
		Console.WriteLine(b + " * " + x + " + " + a + " * " + y + " = " + ggT);
		Console.WriteLine(b * x + a * y == ggT ? "Stimmt!" : "Stimmt net!";);
	}
	Console.ReadKey();
}

private static void ExtendedEuclidian(int a, int b, out int ggT, out int x, out int y)
{
	if (a%b == 0)
	{
		x = 0;
		y = 1;
		ggT = b*y;
		return;
	}

	int dggT, dX, dY, divRem;
	ExtendedEuclidian(b, a % b, out dggT, out dX, out dY);
	x = dY;
	y = dX - dY * Math.DivRem(a, b, out divRem);
	ggT = a * x + b * y;
}

Hatte noch ein Pseudocodeschnippsel in alten Vorlesungsunterlagen ....

*EDIT*: Formatierung angepasst.

21.01.2010 - 13:21 Uhr

Ok, ich habs teilweise selbst gelöst indem ich den eingebetten Typ statt mit static:Enums+Type statt static:Enums.Type angebe. Nun spinnt nur noch mein ValueConverter aber das ist eine andere Baustelle.

21.01.2010 - 11:46 Uhr

Hallo,

das DataBinding an Enums wurde ja schon häufiger besprochen aber meist geht es dabei um ein spezifisches Enum und einem ObjectDataprovider. Ich versuche gerade einen generischen Ansatz mittels IValueConverter, kriege aber die Bindung nicht richtig hin.

Folgendes Szenario:

ich habe eine statische Klasse namens Enums im Namespace Statics in der alle Applikationsweit genutzten Enums definiert sind. Dann habe ich eine WPF Combobox wie folgt definiert:

<ComboBox ItemsSource="{Binding Source={x:Type statics:Enums.Type} , Converter={StaticResource convEnum}}" Style="{DynamicResource comboBoxTemplate}" SelectedItem="{Binding CurrentObject.Type, Mode=TwoWay}" Width="230" Name="cbType"/>

Hier gibt es schon das erste Problem - das Visual Studio meckert bei x:Type statics:Enums.Type das er einen nicht eingbetteten Typ erwartet ("Not nested Type expected!";). Also habe ich mal den Enum als Pfad angegeben: Path=Type aber dann bekomme ich zur Laufzeit eine Binding Exception da Type ja keine Property sondern nur ein Enum ist.

Wie kriege ich hier ein DataBinding hin ohne auf meine Statische Enum Klasse verzichten zu müssen?

PS: Nur falls wer drüber stolpert - Type ist natürlich nicht der Name des Enums sonder der heisst ein wenig anders.

21.01.2010 - 10:00 Uhr

Wie dN!3L schon sagte - kein "lazy loading" im Entity Framework und zwar mit Absicht. Ist ne Designentscheidung von MS. Du kannst das Problem auf zwei Arten lösen.

  1. Explizites Laden durch Aufruf von:
Customer[1].Person.Load();

Uu. musst Du nicht Person.Load() sondern PersonReference.Load() aufrufen.Hängt davon ab ob Du einen 1-1 oder 1-n Beziehung in der DB hast.

  1. Erweitern des generierten EF Codes. Dazu suchst Du die die Person Property die wahrscheinlich so aussieht:

public EntityCollection<Person> Person

{
get
{
return ((IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<Person>;("Model.FK_Person_Customer", "Person";);
}
}

und erweiterst sie so:


public EntityCollection<Person> Person

{
get
{
var retVal = ((IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<Person>;("Model.FK_Person_Customer", "Person";);

if(!retVal.IsLoaded)
retVal.Load();

return retVal;

}
}

Bei der zweiten Lösung besteht die Gefahr, daß der Generator des EF deinen Code überschreibt wenn Du was an der Datenbank änderst. Hat aber den Vorteil, daß Du deinen EF Klassen wirkliches "lazy loading" beibringst.

14.01.2010 - 15:36 Uhr

Den Effekt kann man abmildern, wenn man die Bilder vor dem Vergleich weichzeichnet oder sogar weich auf z.B. 25% Größe runterrechnet.

Und genau diesen Effekt nutzt man bei der Anlichkeitsanalyse durch Bildpyramiden wenn man zum Beispiel sich überlappende Bilder zu einem Panorama Bild zusammenfügt. Ein Bildpyramide besteht ja in der Regel aus dem Original, einem 50% und einem 25% Bild.

Sei es, wie es sei - alle haben recht. Es kommt hierbei eben ganz erheblich darauf an, was man als Unterschied zwischen 2 Bildern ansieht und nur darauf zielte meine Frage.

PS: Mein Beispiel war wirklich unfair. Stell Dir einfach vor, das Bild wäre doppelt so groß und schon ist der Unterschied nur noch 25%.

14.01.2010 - 14:51 Uhr

Hmm, herbivore, meinst Du wirklich. 😉

[Querulantenmodus]

Im Dateianhang findest Du dein Userbild (bitte nicht gleich verklagen), dein Userbild um genau 2 Pixel in x- und y Richtung verschoben, daß Differenzbild und 2 Histogramme des Differenzbildes. Das erste dient nur zum Pixelzählen (es gibt 6800 Pixel) und das zweite zum zählen aller Pixel im Differenzbild, welche ungleich 0 sind (3334 Pixel). Macht rein rechnerisch einen Bildunterschied von 50.97 %, obwohl das Bild nur um 2% in x und 3% in y Richtung verschoben wurde.

[/Querulantenmodus]

Wobei ich zugebe, daß das Beispiel ein wenig unfair ist.

14.01.2010 - 11:33 Uhr

Nur mal so als Zwischenfrage: Was ist den für dich ein Unterschied zwischen zwei Bildern?

Theoretisch kann der Bildunterschied im Pixelvergleich bei 100% liegen wenn das eine Bild zum anderen nur um eine einzige Zeile (oder Spalte) verschoben ist. Wenn das gewünscht ist so reicht Dir der Pixelvergleich - wenn es Dir jedoch nicht auf die Pixel sondern die Merkmale ankommt muss Du einen deutlich aufwendigeren Ansatz wählen, also den Bildinhalt Translations-, Rotations- und vielleicht sogar Skalierungsinvariant machen. Stichwort wäre dann hier eine Frequenzanalyse zB. mittels Fourier oder DCT.

11.01.2010 - 18:38 Uhr

Ohne jetzt die Mathematik im einzelnen zu überprüfen, aber hast Du beachtet, daß Math.Sin und Math.Cos als Eingabe Radiant benötigen und nicht Grad?

Ich habe jetzt einfach mal folgende Codezeilen:

 SINUS = Math.Sin(BETA);
COSINUS = Math.Cos(BETA);
 

durch

 SINUS = Math.Sin(BETA * Math.PI/180);
COSINUS = Math.Cos(BETA * Math.PI/180);
 

ersetzt und das Ergebniss sieht ganz passabel aus - obs stimmt weiss ich jedoch nicht (bin im Moment zu faul das Mathemodul in meinem Hirn anzuwerfen).

07.01.2010 - 18:12 Uhr

Zur Entropie:

Bei der globalen Berechnung ist die Entropie nichts anderes als ein Maß für den Informationsgehalt eines Bildes (Information == Unterschiedliche Farben/Grauwerte). In der Regel wird eine globale Berechnung gemacht um einen möglichen Kompressionsgrad für ein Bild zu bestimmen da der Betrag der Entropie in einem Grauwertbild zB. die Anzahl von Bits angibt die nötigt sind um alle vorhandenen Grauwerkombinationen abzudecken. So ist der Betrag der Entropie eines Bildes mit nur einem Grauwert = 0 und der Betrag der Entropie eines Bildes mit gleichmäßiger Verteilung von 256 Grauwerten = 8.
Zudem ist die Entropie ein Maß für die Verteilung der unterschiedlichen Grauwertkombinationen. Je größer der Wert desto "gleichverteilter" (blödes Wort) sind die möglichen Grauwertkombinationen in einem Bild. Regional betrachtet lassen sich mittels der Entropie recht schnell homogene (in Bezug auf die Verteilung der Grauwertkombinationen) von inhomogenen Bildbereichen unterscheiden. Stichwort wäre hier die sog. Coocurrence Matrix zur quantitativen Bildanalyse.
Deine Formel ist an sich richtig, ich würde sich jedoch eher so schreiben:

-sum(p(g) * log(p(g)))

wobei p(g) die Häufigkeit des Grauwertes g innerhalb des Bildes ist.

Zur Energie:

Die Energie (wird auch als Second Angular Moment bezeichnet) wird ebenfalls aus der Coocurrence Matrix abgleitet nach der Formel:

sum(p(g)*p(g))

wobei p(g) die Häufigkeit des Grauwertes g innerhalb des Bildes ist.

Von daher sind eigentlich beide Formeln die du gefunden hast nicht richtig, da die sich nur auf die Werte selbst und nicht auf die Häufigkeiten beziehen. Die Energie ist das genau Gegenteil der Entropie, dh. sie wird größer je kleiner die Anzahl der vorhandenen Grauwertkombinationen ist. In einem absolut homogenen Bild (bezogen auf die Grauwerte und nicht die Grauwertkombinationen), also einem Bild mit nur einem Grauwert hat die Energie den größten möglichen Wert.

Beide Merkmale (also Energie und Entropie) werden als Haralicksche Texturparameter bezeichnet da sie insbesondere in der Texturanalyse verwendet werden.

Soweit mein theoretisches (und hoffentlich noch richtiges) Vorlesungswissen - ist aber schon ein paar Jahre her 😉.

Bei deinen beiden Energieformeln ist noch folgendes zu sagen:

Imho sind beide Formeln bezogen auf die Energie Unsinn. Sie normieren das Bild nur und das tut die zweite Formel besser als die erste da sie eine zusätzliche Gewichtung des Farbraumes vornimmt. Ich bin mir nicht ganz sicher, aber ich meine die angegebenen Parameter entsprechen dem sRGB Farbprofil und sind sinnvoll um zB. in den HSL Farbraum umzurechnen - zumindest bin ich bei Farbtransformationen schonmal über diese Parameter gestolpert müsste jedoch nochmal in den Code kucken.

Beim Farbhistogramm ist die Beschreibung imho richtig. Der Farbdurchschnittswert und die Farbsumme gehört imho nicht zum Histogramm da ein Histogramm nur ein Maß für die Verteilung unterschiedlicher Werte im gesammten Wertebereich ist. Trotzdem sind natürlich die Summe, der Durchschnitt und der Median statistische Parameter die sinnvolle Aussagen zu einem Bild machen können - je nach Bild natürlich.

22.10.2009 - 15:28 Uhr

Hallo,

ich habe im Moment folgendes Problem. Ich habe eine Menge von UserControls in einer Klassenbibliothek. Innerhalb dieser Bibliothek gibt es auch ein ResourceDictionary damit alle Steuerlemente innerhalb der Controls gleich aussehen. Für die UserControls gibt es ebenfalls einen Style (<Style TargetType="UserControl"> ...).

Wenn ich nun diese UserControls in meine Applikation einbinde wird dieser UserControl Style ignoriert. Das ganze sieht erst dann wieder gut aus, wenn ich in der App.xaml einen identischen Style mit dem Klassennamen des UserControls anlege (<Style TargetType="my:ctrlMeinControl"> ....).

Eigentlich ja auch ganz logisch, da ich ja nicht der abgeleiteten Klasse den Style zugewiesen habe sondern der Basisklasse UserControl. Dennoch ist das ganze irgendwie unpraktisch da ich nun in meiner Applikation für jedes meiner Controls (15 und es werden täglich mehr) einen eigenen Styleeintrag anlegen muss der identisch zu dem UserControl Eintrag im ResourceDictionary ist. Da sind die Probleme fast vorprogrammiert - im wahrsten Sinne des Wortes.

Geht das nicht irgendwie eleganter?

*EDIT*: Es geht nun ein bisschen besser, wenn ich statt dem UserControl dem Grid (im Moment hat jedes UserControl eines) die Eigenschaften zuweise - aber irgendwie ist das nicht der Weisheit letzter Schluß.

09.08.2009 - 17:18 Uhr

Danke!

Bin vor nem halben Jahr mal über AntMe! gestolpert und habe das Projekt ganz vergessen. Vielleicht finde ich da was ....

09.08.2009 - 17:00 Uhr

Hallo,

bin mir nicht sicher ob es das richtige Forum ist. Es ist noch kein vollständiges Projekt sondern eher eine kleine Spielerei an der ich seit gestern arbeite und im Moment brauche ich ein wenig Input.

Kurzbeschreibung

RoboSwarm soll koordiniertes Verhalten von kleinen Robotern simulieren. Eigentlich ist es nur ein großes Spielfeld, auf der zufällig verteilt Roboter von 2 Teams mit unterschiedlichen Strategien versuchen zu gewinnen. Das Team, welches am Ende noch Bots hat, hat gewonnen. Die Verteilung (Position) und auch die jeweilige Strategie werden zufällig bei Programmstart festgelegt. Die Angriffs- und Verteidigungsstärke sowie die Geschwindigkeit aller Bots ist immer gleich.

Strategien

Im Moment existieren vier verschiedene Strategien:1.AVOIDER (HIDE): Ein Bot mit diese Strategie versucht alle Bots aus dem gegnerischen Team aus dem Weg zu gehen und greift niemals einen anderen Bot an. Er ist ein absoluter Feigling. 1.FOLLOWER (FOLLOW_FRIEND): Ein solcher Bot versucht sich an den erstbesten HUNTER ranzuhängen und folgt diesem auch wenn er aus der Sichtweite gerät. Kommt ein gegnerischer Bot in seine Waffenreichweite wird dieser beschossen aber nicht weiterverfolgt. 1.HUNTER (FOLLOW_ENEMY): Sobald ein Gegner in Sichtweite gerät verfolgt der HUNTER ihn solange er in seiner Sichtweite bleibt. FOLLOWER hängen sich an die Hunter und bilden so ein durchaus gefährliches Rudel. 1.RENEGADE (FIRE_AT_WILL): Agiert auf eigene Faust, folgt niemanden, hat keine Anhänger und schiesst auf alle Gegner die er sieht.

BOT EigenschaftenEin Bot (definiert in der Klasse cBot) hat folgende wichtige Eigenschaften: 1.SensorRange: Sichtweite des Bots in der er Gegner und Freunde sehen kann. 1.MaxWeaponRange: Maximale Reichweite seiner Waffen 1.MinWeaponRange: Minimale Reichweite seiner Waffen und Mindestabstand der Bots 1.WeaponPower: Angriffstärke 1.DefensePower: Verteidigungsstärke 1.TeamID: GUID seines Teams 1.Disabled: Zeigt an, ob er tot ist oder nicht 1.BotToFollow: Aktuell "verfolgter" Bot (Freund oder Feind) 1.FiringAt: Bot der gerade anvisiert wird 1.Name: Name des Bots 1.Strategie: Strategie des Bots

ProgrammablaufDas ganze ist Timer gesteuert, dh. pro Tick werden für alle Bots zunächst die Bewegungen und danach die Angriffe ausgeführt. Es sind atm noch viele Schleifendurchläufe nötig, die wegrationalisiert werden müssen. Die Bewegung wird über die Funktion ExecuteMovementOrders ausgeführt wo der einzelne Bot seine Umgebung analysiert (Freunde bzw. Feinde findet), nach seiner Strategie sich bewegt und im zweifelsfalle am Spielfeldrand seinen Bewegungswinkel ändert. Die Angriffe werden über die Funktion ExecuteFireOrders ausgeführt, wobei hier alle Bots, bis auf die AVOIDER sich einfach den nächstbesten Gegner suchen, fall sie nicht schon einen haben. ****
Oberfläche

Die Oberfläche ist eine simple Form ohne Steuerelemente. Darauf zu sehen ist das Spielfeld und alle Bots sowie deren Beziehungen. Die Symbole und Linien haben dabei folgende Bedeutung:

Rechteck(Teamfarbe): FOLLOWER
Ausgefülltes Rechteck (TeamFarbe): HUNTER
Kreis (TeamFarbe): AVOIDER
Ausgefüllter Kreis (TeamFarbe): RENEGADE
Ausgefülltes Rechteck (Grau): "toter" Bot

Linie (Fuchsia): FOLLOWER folgt HUNTER oder HUNTER folgt einem Feind
Linie (Gold): Bot feuert

Bild

Hinweise

Das ganze läuft im Moment noch sehr langsam bei einer großen Zahl Bots, da ich der Performance im Moment keine Priorität einräume (ist eh nur ein Experiment).

Projektbeschreibung

Das Projekt ist ein Visual Studio 2008 Projekt. Es enthält folgende Klassen:
1.mainFrm: Die Form und gleichzeitig der Einstiegspunkt 1.cBot: Klasse für die instanzierung der Bots. Eigenschaften und Strategien der Bots sind hier 1.cBoundary: Begrenzung des Spielfelds 1.cVector: Bewegungsvektoren für die Bots 1.cRSEnum: Enums (im Moment nur die Strategien) 1.cTeam: Klasse zur Instanzierung der Teams

**... und was soll das jetzt?**Ich stecke im Moment fest. Zwar bewegen sich alle Bots, aber deren Bewegungen sind doch sehr unkoordiniert. Ich denke ich bräuchte Entscheidungshilfen, was welcher Bot wirklich tun soll. Des weiteren bin ich im Moment nicht ganz sicher ob das Konzept wirklich richtig ist. Wenn sich wer mit Swarm Theorien auskennt und ein paar Hinweise hat wäre ich wirklich sehr dankbar. Und wenn jemand einfach nur mal schauen will und weitere (auch programmtechnische) Hinweise hätte wäre ich ebenfalls sehr dankbar. Wie bereits gesagt, im Moment ist es nur ein Experiment aber ich denke es könnte mehr sein ....
PS: Ich mag den WYSIWYG Editor nicht grml

04.07.2009 - 19:36 Uhr

Ok, sorry. War nur nach der Woche ein wenig angepisst da ich 4 Apps von 3 verschiedenen Entwicklern fixen musste und froh gewesen wäre, wenn die "Fehler" nur in solchen try..catch Blöcken oder endlos verschachtelten if Abfragen zu finden gewesen wären ... da verstehe ich ja wenigstens was der Entwickler wollte.

Also, ich wollte niemanden zu nahe treten.

Aber ein "Schmuckstück" dieser Woche wollte ich dann doch noch teilen:


bool parseData(SerialPort port)
{
port.DiscardInBuffer();

try
{
if(port.ReadLine().Contains("* blablabla1 *)) parseData(port);
else if(port.ReadLine().Contains("* blablabla2 *)) parseData(port);
else if(port.ReadLine().Contains("* blablabla3 *)) parseData(port);
else if(port.ReadLine().Contains("* blablabla4 *)) parseData(port);
else if(port.ReadLine().Contains("* blablabla5 *)) parseData(port);
else if(port.ReadLine().Contains("* blablabla6 *)) return true;
}
catch(TimeOutException) { return false; }
}

Und der Entwickler fragt mich noch warum das so nicht funktioniert ....

04.07.2009 - 12:04 Uhr

Hmm,

der einzige "Horror" ist, daß die abzufangende Exception nicht spezifiziert ist - ansonsten hätte ich mindestens einen sinnvollen Einsatzzweck für ein solches Konstrukt: Die TimeoutException beim SerialPort.

Allerdings sehe ich den Horror bei einigen Beiträgen hier im Strang nicht - manches ist einfach nur Bad-By-Design und anderes würde ich auf Zeitdruck schieben. Wer immer perfekten Code schreibt werfe den ersten Stein ...

Auch ich habe diese Woche mindestens 2 mal Code geschrieben der hier im Thread wahrscheinlich als "Horror" angesehen würde - aber wenn die Produktion auf ein Tool wartet und der Entwickler nicht mehr da ist habe ich nur zwei Möglichkeiten - schnell nen Fehler "unsauber" beseitigen und riskieren hier zu landen oder 20 Leuten sagen zu müssen das sich eine Serieneinführung eines Produktes leider wegen eines aufwendigen Code Reviews um 2 Tage verschiebt und das dem Unternehmen Kosten in Höhe von 200.000 Euro beschert. Die Entscheidung fällt da leicht ...

Sowas:


++x += –x *= ++x -= -x; // Mal im INet gefunden

ist Horror oder eine Applikation die eine serielle Kommunikation in etwa so realisiert:


port.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.port_DataReceived);
port.Writeline("blablabla";);
Thread.Sleep(1000);
string data = port.ReadLine();
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.port_DataReceived);

und das geschätzte 500 mal innerhalb der Applikation.
Auch sehr beliebt ist es eine Applikation die via Knopfdruck USB Daten austauscht um eine automatische Abfrage zu erweitern welche sich nicht mit der manuellen Abfrage synchronisiert. Der Anwender darf dann das beliebte "Hoffentlich hats geklappt" Lotto spielen wenn er Manuell Daten senden oder empfangen möchte.

17.06.2009 - 18:51 Uhr

*EDIT* Gelöst. Siehe unten.

Folgendes Problem treibt mich gerade in den Wahnsinn:

Ich habe eine Fremdanbieter C++ DLL welche sich nicht in C# einbinden lässt (keine COM). Zudem wird innerhalb der DLL eine Klasse instanziert so daß auch der Umweg über DLLImport nicht so ohne weiteres geht. Also habe ich mir in Managed C++ einen Wrapper für die Dll geschrieben und das ganze hat sauber funktioniert. Nun wurde die Dll erweitert und jetzt kriege ich eine ganz simple Parameterübergabe einfach nicht hin.

Die aufzurufende C++ Funktion hat folgende Signatur:

Fehlerwert getValue(enumValueAddress adress, unsigned int *_iValue);

Damit die Zuordnung der Werte einfacher wird habe ich einfach eine Klasse (in Managed C++) geschrieben welche die Werte enthält:


public ref class Values
{
public:
enumValue1 Value1;
enumValue2 Value2;
// ... usw ...};

Der Managed C++ Klasse wird diese Klasse aus dem C# Bereich als Call-by-Reference übergeben - alles in Ordnung. Nun will ich aber die C++ Funktion der Dll aufrufen:


getValue(enumValueAddres::Adress1, (unsigned int *)cValues->Value1);

Der Compiler meldet keinen Fehler, aber wenn ich mir den Wert Value1 im Debugger anschaue so ist dieser Wert nach dem casten auf unsigned int* ungültig. Es geht also um einen simplen Cast eines Enum Wertes auf einen unsigned int Pointer - was mache ich falsch?

Lasse ich den Cast Weg, meckert der Compiler wegen unverträglicher Typen. Versuche ich den Adress Operator (&;) meckert der Compiler auch.

PS: Alle Funktions- und Wertenamen sind abstrahiert. Nicht wundern bitte, aber der vollständige Code würde gegen diverse NDA's verstossen. 😉

*EDIT*
Habs gelöst. Einfach eine temporäre unsigned int Variable nehmen (im Managed C++ Bereich), via & in die Funktion und danach auf den gewünschten Enum casten.

11.06.2009 - 09:37 Uhr

Nicht so kompliziert denken.

Im WinForms Projekt erstellst Du Dir ein WinForms User Control welches einen ElementHost beinhaltet. Dann noch ein WPF User Control mit einem ViewPort. Nun das WPF User Control dem ElementHost zuweisen und du hast deine Visualisierungsoberfläche.

Mein Empfehlung wäre, daß Du die XML Daten in XAML extern konvertierst und dann via XAML Reader einliest. Wie das bei Google Sketchup Modellen gemacht werden kann habe ich hier mal beschrieben:

http://www.vbarchiv.net/forum/read.php?f=10&i=61389&t=61389

ist zwar VB.Net aber die paar Funktionen sind schnell konvertiert.

Der Link zum Flux Studio hat sich allerdings geändert:
http://mediamachines.wordpress.com/

11.06.2009 - 09:35 Uhr

*doppelt*

16.05.2009 - 09:19 Uhr

Als Open Source kenne ich nichts. Aber hol Dir das Buch von Petzold ("
3D Programming for Windows" - http://www.charlespetzold.com/3D/index.html). Dort gibt es folgendes XPAB Beispiel:

http://www.charlespetzold.com/3D/MouseTracking/MouseTracking.xbap

Die Achsen sind Bestandteil von Petzolds 3D Bibliothek. Um die zu Verwenden musst Du aber ein Exemplar des Buches haben.

Wenn Du jedoch mehr mit WPF 3D machen willst rate ich Dir deine eigene 3D Bibliothek zu schreiben da die von Petzold nur für kleine Beispiele ausgelegt ist und er einige entscheidende Performancefehler macht bzw. die Hinweise zur Performancesteigerung nicht umgesetzt hat.

*edit*
Wenn Du eine schnelle Lösung selbst programmieren willst - es ist nicht schwer. Du kannst die Achsen ja als GeometryDrawing erstellen und dann einfach als Textur auf 3 2-Dimensionale Rechtecke legen die Du im Raum anordnest.

24.04.2009 - 10:54 Uhr

Nur nochmal als Hinweis. Ich habe den Code ein wenig verändert und schon läuft es auch bei 150 * 150 Quadraten (auf einer GeForce 8600) noch flüssig.

Statt jedem Triangle eine eigene Modelgroup zuzuweisen werden nun die Cubes als MeshGeometry erstellt, daraus ein GeometryModel3D mit Textur erzeugt und diese Modelle dann nur einer! ModelGroup zugewiesen. Nachteil ist, daß man die TriangleIndzies manuell zuweisen muss, was ein bisschen Nachdenken erfordert. Aus Faulheit habe ich die Berechnung der Normals WPF überlassen, da könnte man noch optimieren. Auch habe ich noch kein "Freeze" verwendet - da ist also noch viel Potential.

Ist ja auch nur um zu zeigen, daß es schneller geht ....

PS: Die Indizes stimmen noch nicht ganz, wie man in der Animation sieht - hab im Moment aber nicht so viel Zeit.

23.04.2009 - 22:34 Uhr

Ich vermute mal das meine Antwort zu spät kommt, aber an Optimierungen ist in deinem Code noch einiges möglich.

  1. Dem ModelVisual3D so wenig ModelGroups wie möglich hinzufügen. WPF verwendet für jede ModelGroup im Visual eine eigene Renderpipeline. Statt also jeden Cube dem Visual hinzuzufügen solltest Du sie vorher in eine ModelGroup packen und nur diese dem Visual hinzufügen.

  2. So häufig wie irgend möglich Freezen. Jede fertige Geometry, Textur oder Modelgroup via "CanFreeze" abfragen ob man "Freeze" aufrufen kann und es dann auch tun. Das spart Speicher und bringt Performance.

  3. Unnötige "Faces" vermeiden. Statt jeden Cube mit Seiten zu versehen solltest Du das Schachbrett eher aus Rechtecken zusammensetzen. Die Seiten sieht eh keiner, aber sie belasten den Rendervorgang.

  4. Wenn möglich beim ViewPort3D die Eigenschaften "IsHitTestVisible" und "ClipToBounds" auf false setzen. Hinter beiden stehen reine Softwareroutinen und die fressen Rechenzeit.

  5. Alles was die gleiche Textur hat wenn möglich in einer MeshGeometry erschlagen und dann eher via TextureMapping arbeiten.

  6. Statt das Schachbrett durch einzelne Cubes zu realisieren ist es sinnvoller einen Cube zu nehmen und das Schachbrettmuster durch TextureMapping zu erzeugen - fordert zwar ein bisschen Hirnakrobatik, ist aber extrem Performancesteigernd.

  7. Mir fallen mit Sichrheit noch Sachen ein ... bei Bedarf kann ich mal versuchen deinen Code zu optimieren.

WPF ist bei richtiger Verwendung nicht so langsam - bei meinem GIS Viewer waren teilweise bis zu 15.000 Spheres a 32 Faces (das waren die Hausnummern 😉 ) und noch ca. 500 Polygone mit im Schnitt 8 Stützstellen sichtbar. Und das ganze war immer noch flüssig trotz Transparenz Effekten, BitmapBrushes und PointLights. Von daher halte ich die Aussage, daß WPF nur was für 2D ist für etwas überheblich und durch praktische Arbeit in meinem Fall auch für widerlegt. Auf der MSDN gibt es och ein paar Performance Tipps, bzw. Hinweise, was unter WPF langsam ist und was nicht.

23.04.2009 - 17:38 Uhr

Hallo Swen,

das Problem bei DNG's ist, das das File Format nur ein Container ist in dem sich quasi alles befinden kann (BMP, Jpg) und auch jedes beliebige Pixel Format inklusive Anordnungen nach dem Bayer Pattern und sogar mehrere Bilder. Du hast eigentlich nur 2 Möglichkeiten:

  1. Einen Wrapper im die Bibliothek von Adobe zu schreiben (http://www.adobe.com/support/downloads/dng/dng_sdk.html)

  2. Das Bild als ByteArray parsen und nach den Tags suchen, welche in der Spec stehen (http://www.adobe.com/products/dng/pdfs/dng_spec_1_2_0_0.pdf)

Alternative 1. ist viel Arbeit - ich habe es nach 3 Tagen aufgegeben. Alternative 2 ist schneller, setzt aber vorraus, daß Du weisst was sich in dem DNG befindet.

Ich nehme an, daß die DNG's von denen Du sprichst Rohdaten einer Digital Kamera sind. Zeigt IrfanView wirklich das korrekte Bild oder ist es ein wenig zu dunkel? Wie sieht die Anzeige in Photoshop Elements aus?

Bei DNG's müssen rechte viele Sachen beachtet werden (White Balance, Active Image Area, Bayer Pattern usw.). Eine simple Anzeige kann dich schon ein paar Tage Arbeit kosten - und wenn Du dann noch mit den Bilddaten arbeiten willst wirds noch komplizierter.

03.04.2009 - 10:11 Uhr

Herbivore, Du kriegst ein Bussi. 😄 Vielen Dank.

Control.Invoke seltener aufrufen ist billiger 😃 Das wars. Statt wie vorher jedes Steuerelement über eine eigene Invoke Methode zu aktualisieren (was teilweise zu 20 Invokes hintereinander führte) gibt es nun eine allgemeine Update Methode und somit nur noch ein Invoke - und sieh da, es läuft wieder.

PS: Die Aussage zu BeginInvoke und EndInvoke habe ich von hier: http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml

Da steht zumindest:

Invoke is used to execute the delegate synchronously (i.e. a line of code such as myDelegate(); is actually compiled as myDelegate.Invoke();). The other two methods are for asynchronous execution, and must always be called as a pair - every BeginInvoke must be matched by a call to EndInvoke somewhere to guarantee that you don't leak resources.

Allerdings habe ich gerade gesehen das sich der Autor damit selbst wiederspricht da er auch schreibt:

We don't call EndInvoke after the BeginInvoke. Unlike all other asynchronous methods (see the
>
you don't need to call EndInvoke unless you need the return value of the delegate's method. Of course, BeginInvoke is also different to all of the other asynchronous methods as it doesn't cause the delegate to be run on a thread pool thread - that would defeat the whole point in this case!

03.04.2009 - 08:23 Uhr

Danke für die Antwort - das war auch meine Vermutung. Aber die einzelnen Worker schliessen ihre Verarbeitung alle ab (die Breakpoints am Ende der do_work Mothoden werden alle erreicht). Nur das WorkerCompleted Event kommt nicht. So als würde der Eventhandler nicht mehr registriert sein ...

Wie kann ich eigentlich im Debugger sehen welcher Eventhandler an den BackgroundWorkern registriert ist?

Es fliegt auch keine Exception (in der aktuellen Einstellung sollte der Debugger bei jeder möglichen Exception anhalten).

Welche Methode wäre denn "billiger" als Invoke? Ich meine gelesen zu haben, daß Invoke besser als BeginInvoke ist, da hierzu auch immer ein EndInvoke gehören muss um Speicherlecks zu vermeiden.

Ich werde heute mal versuchen die Synchronisierung statt in den WorkerCompleted Events schon in der do_work Methode durchzuführen - irgendwie habe ich dabei Bauchschmerzen, aber vielleicht ist das ja die Lösung. Und wenn alles nichts hilft werde ich statt der BackgroundWorker normale Threads verwenden.

02.04.2009 - 18:22 Uhr

Folgendes Szenario:

Ich habe ein etwas aufwendiges Prozessing bei dem ich große Bilddaten Filtere und Untersuche. Damit das ganze sauber läuft habe ich das Processing in einen Backgroundworker ausgelagert. Ein bestimmter Prozess ist jedoch so aufwendig das ich alle Prozessorzeit brauche die ich kriegen kann. Deshalb wird dieser Prozess auf 8 weitere BackgroundWorker ausgelagert (bei einem QuadCore kriege ich so 100% Auslastung hin). Der HauptThread schläft während die anderen 8 werkeln.

Es funktioniert also so:

Form -> Startet BackgroundWorker -> Startet 8 weitere Backgroundworker und legt sich schlafen (über ein ManualResetEvent). -> Backgroundworker melden sich zurück und wecken den Haupthread wieder auf.

Bis gestern lief alles Prima. Nun habe ich heute die GUI erweitert. Alle Controls der GUI werden natürlich Threadsicher via Invoke aufgerufen und das hatte bei einer kleinen Menge von Controls ja auch wunderbar geklappt.

Aber nun passiert folgendes: Der Haupthread macht seine Arbeit und zeigt diverse Werte an, gelangt an den Punkt wo er die 8 anderen Worker starten soll, diese Starten auch aber nun wird deren CompletedEvent nicht mehr aufgerufen obwohl die eigentliche Arbeitsmethode abgeschlossen wurde und der Haupthread schläft bis in alle Ewigkeit.

Passe ich den Haupthread so an, daß nur die 8 Worker gestartet werden und deren Ergebnisse anzeigen funktioniert alles wunderbar - sobald ich jedoch die anderen arbeitsintensiven Methoden wieder einbaue passiert das obige. Die anderen Methoden brauchen ca. 1,5 Minuten bis ich zu dem Punkt komme an dem die 8 Threads gestartet werden und bringen in der Zeit ca. 140 Steuerelemente auf den neusten Stand.

Da die einzige Änderung in der Anzahl der Controls (vorher 5 nun ca. 150) und dementsprechend in der Zahl der Invoke Aufrufe liegt vermute ich dort den Fehler - aber ich sehe nichts im Stack und auch der Threadpool ist soweit in Ordnung.

Vielleicht ist es nicht unbedingt der sinnvollste Weg aus einem Backgroundworker weitere zu starten aber bevor ich die ganze Anwendung umstrukturiere wollt ich mal fragen ob ich den Fehler vielleicht an anderer Stelle suchen sollte.

Noch ein Hinweis: Die 8 Backgroundworker haben keine Schleife sonmdern jeweils nur 3 Methoden - diese jedoch werden aus Performance Gründen im unsafe context aufgerufen.

20.03.2009 - 13:16 Uhr

Das würde ich erstmal auch so sehen - wie bereits gesagt, wenn Du direkt im Bytearray arbeitest und unnötiges Casten vermeidest sparst Du schon ne Menge Zeit. Arbeite nicht mit Strings, wenn Du sie nicht brauchst - Strings sind langsam und groß. Auch das Anlegen von Variablen während der Auswertung ist zeitintensiv. Im schlimmsten Fall musst Du halt während der Auswertung das Bytearray fixen und dann mit Pointern weiterarbeiten - das würde ich jedoch zunächst versuchen zu vermeiden.

20.03.2009 - 12:25 Uhr

Hmm, das ist ja alles schön und gut, aber klärt den wichtigsten Punkt nicht: Wie lange dauert deine Auswertung?

Nimm doch einfach die Stopwatch Klasse und messe genau nach wie lange die einzelnen Funktionen brauchen. Wichtig wären hier DataRecieved und die Auswertung.

Und das Dir das Programm abstürzt, wenn Du 200 mal in der Sekunde einen Invoke auf eine Textbox machst ist nicht weiter verwunderlich. Auch ein Invoke braucht Zeit und dazu kommt die Zeit der Auswertung und des Datenempfangs. Wenn diese Zeiten zusammen unter 5ms bleiben sollen brauchst Du einen wirklich schnellen Rechner und solltest das ganze eher in C++ als in C# realisieren. Deshalb ist deine 1. Vermutung (Threadpool) nicht so falsch - wenn Empfang, Auswertung und Ausgabe nur 6 ms braucht (was sehr kurz ist) hast du nach 6s mindestens 200 parellele Auswertungen noch offen (6s/6ms = 1000, 6s/5ms = 1200 --> 1200 Telegramme aber nur 1000 Auswertungen).

Deshalb wiederhole ich mich nochmal - wenn deine Daten so häufig kommen schreib für die Auswertung und Ausgabe einen eigenen Backgroundworker welcher mit dem Empfangsthread über eine gelockte Queue kommuniziert. Am Anfang der do_work Methode holst Du dein Telegramm aus der Queue und gibst sie wieder frei. Sollte die Queue dann immer größer werden musst Du in der Auswertung halt Finetuning betreiben (zb. nicht mit Strings arbeiten sondern direkt auf dem ByteArray). Die nächste Optimierung wäre statt ReadByte im DataRecieved ein ReadExisting und ein ReceivedThreshold von 6. Und last but not least - wenn die Datenrate wirklich so groß ist probier mal das ganze im Release statt im Debugmode.

18.03.2009 - 19:58 Uhr

Sorry, ich kann meist erst Abends antworten.

Ich kenn die interne Implementierung des SerialPorts nicht auswendig aber mWn. gibt es nur einen Thread darin. Die Events sind ja keine eigenen Threads sondern nur Signalisierungszustände des selben.
Allerdings ist es richtig - solange Du im DataReceived Event was tust kann der Serialport kein zweites DataReceived Event erzeugen. Wäre auch sehr gefährlich wenn die Implementierung so wäre - man könnte sich ja nie sicher sein, welchen Teil eines Pakets man gerade ausliest. Das gleiche gilt natürlich auch für die PinChanged und ErrorReceived Events.
Deshalb sollte man in dem Event (und das gilt grunsätzlich für alle Events) keine Zeitaufwändigen Arbeiten - wie zB. eine Auswertung - durchführen.

Ich implementiere das ganze idR. so, daß ich eine Threadsichere Queue habe in die ich im DataReceived Event einfach nur reinschreibe und einen BackgroundWorker der die Queue überwacht und im zweifelsfalle auswertet. Damit hat man nur 2 Threads - den des SerialPorts und den der Auswertung. Und selbst bei 115.000 Baud verschluckt sich da nix.

In deinem Falle würde ich einfach versuchen die Auswertefunktion via Invoke (zb. mit dem MethodInvoker und einem globalen gelockten Puffer) aufzurufen - damit startest Du zwar einen neuen Thread und es kann im schlimmsten Falle passieren, daß die Methode 2 mal gestartet wird, da das DataReceived Event schneller kommt als deine Auswertung braucht, aber wenn die Auswertung Threadsicher ist sollte das eigentlich kein Problem sein. Wenn Die Auswertung allerdings deutlich länger braucht kann das zu Problemen führen da dann 3 oder mehr Auswertethreads gleichzeitig laufen - dieses Problem hat dann seine Ursache jedoch in deiner Auswertemethode, welche zu langsam ist, und nicht im SerialPort.

17.03.2009 - 19:45 Uhr

Nur kleine Anmerkungen:

Was passiert eigentlich, wenn Du den ReceivedBytesThreshold des Ports auf 6 setzt?

Und zum anderen würde ich die Auswertung (unabhängig von der Dauer) nicht im DataReceived Event aufrufen. Deine Daten kommen in recht kurzen Abständen und scheinen sich "zu überholen" - das ist imho ein Hinweis darauf, daß die Auswertung den Datenempfang blockiert. Nimm einfach mal die Auswertung raus und gibt den Pufferinhalt via Console direkt aus - gehen dann auch noch Daten verloren? Falls nein versuch deine Auswertemethode via Invoke aufzurufen - dann blockiert dein SerialPort Thread nicht.

Die hübschere Lösung jedoch wäre alle Daten in einen Threadsicheren Puffer zu packen und deine Auswertung über einen zweiten unabhängigen Thread zu steuern. Die Queue von Floste: Lockfreie threadsichere Queue dürfte sich gut dafür eignen.

17.03.2009 - 07:59 Uhr

Hmm, ich befürchte es ist eine sau blöde Frage, aber ich komme im Moment nicht auf die Lösung. Ich habe eine Basisklasse (WinForm) und mehrere vererbte Klassen (welche wiederrum vererben usw.). Nun brauch ich eine Funktion, die immer aufgerufen wird (in der Basis als auch in den Childs) und welche aber nicht im oder durch den Construktor aufgerufen werden darf. Die Objekte müssen also bereits existieren bevor diese Funktion aufgerufen wird. Trotzdem soll es automatisch funktionieren.

Und ich will den Code nur an einer Stelle ändern und nicht in sämtlichen Childs. Ist sowas überhaupt möglich?

Wie ich grad so schreibe fällt mir ein, daß ich das vielleicht über ein Event steuern kann (die Basis ist ja eine WinForm) ..... aber mal angenommen es wäre keine .....

26.02.2009 - 14:04 Uhr

Wie bereits gesagt - ich vermute den Fehler bei der Semaphore. Diese ist ja eigentlich nicht dazu gedacht nur einem Thread Zugriff zu gewähren sondern sovielen wie im Konstruktor angegeben. Wenn also beim Konstruktor 2 Threads angegeben wurde so können auch beide gleichzeitig in die Routine reinspringen.
Wenn Du wirklich nur einem Thread Zugriff gewähren möchtest ist ein Monitor oder ein lock die bessere Alternative. Ob aber wirklich zwei Threads gleichzeitig in die Routine reinspringen kannst Du ja mittels einer Debugausgabe am Anfang der Routine feststellen.

SerialPort.Open() braucht ca. 5 ms - natürlich abhängig von der Hardware. Meine Vermutung ist - ohne deinen genauen Code zu kennen, daß innerhlab dieser 5 ms versucht wird die Serialport.Open nochmal aufzrufen.

Anbei ein kleiner Codeschnipsel:


public partial class Form1 : Form
{
private SerialPort _localSerial;
private BackgroundWorker _bgWorker1 = new BackgroundWorker();
private BackgroundWorker _bgWorker2 = new BackgroundWorker();
private Semaphore _sem;

public Form1()
{
InitializeComponent();

_localSerial = new SerialPort("COM1";);
_bgWorker1.DoWork += new DoWorkEventHandler(_bgWorker_DoWork);
_bgWorker2.DoWork += new DoWorkEventHandler(_bgWorker_DoWork);

_sem = new Semaphore(3, 3);

_bgWorker1.RunWorkerAsync();
_bgWorker2.RunWorkerAsync();

}

void _bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
_sem.WaitOne();

if (!_localSerial.IsOpen)
_localSerial.Open();

_sem.Release();
}
}

Wird der Code so aufgerufen fliegt eine Exception bei SerialPort.Open() da beide Backgroundworker zeitgleich versuchen auf den Port zuzgreifen.

Ändere ich:

_sem = new Semaphore(3, 3);

zu

_sem = new Semaphore(1, 3);

fliegt die Exception nicht mehr da nur noch ein ThreadSlot für die Semaphore frei ist.

25.02.2009 - 18:44 Uhr

welche Möglichkeit(en) habe ich außer "IsOpen" festzustellen das ein SerialPort bereits geöffnet ist???

Eigentlich keine - denn genau dafür ist die Property ja da. Uu. bekommst Du das Öffnen noch mit, wenn Du auf das PinChanged Event reagierst. Funktioniert natürlich nur, wenn ein Kabel angeschlossen ist und nicht nur die RX,TX und Ground Leitungen verwendet werden.

Die Frage sollte daher eher lauten: Warum zeigt IsOpen an, das der Port geschlossen ist obwohl er es nicht ist? Was mich ein wenig stutzig gemacht hat an deinen Ausführungen ist die Verwendung der Semaphore. Wie kannst Du den damit sicherstellen das nicht zwei Threads auf ein und denselben SerialPort zugreifen? Denn das dürfte der Grund sein warum die IsOpen Property falsch angezeigt wird. Steht der Threadcounter der Semaphore auf 1?

Bau doch einfach mal Testweise ein Sleep(5) nach dem Serialport.Open() ein - steht dann die IsOpen Property immer noch auf false?

20.02.2009 - 14:39 Uhr

@guggu:

Auch ich möchte Dir nicht zu nahe treten, aber weisst Du wirklich worauf Du dich da eingelassen hast? Ich habe letztes Jahr an einem ähnlichen Projekt mitgearbeitet - nur für einen Landkreis. Wir waren zu dritt und die Laufzeit des Projektes ist auf 5 Jahre ausgelegt gewesen. Implementierungszeit sind 2,5 Mannjahre. Und ich hatte an der ein oder anderen Stell schon Muffensausen wenn ein Feuerwehrmann meine Applikation auf eine Art und Weise bediente die ich nicht vorgesehen habe. Menschen der Tat denken immer anders als Entwickler. 😉

Ganz wichtige Themen, die Du unbedingt noch vor der Pilotphase klären solltest:

  1. Haftung (man kann es nicht zu oft sagen).
  2. Datenschutz - ist das ganze innerhalb der Behörde/Einsatzzentrale abgesegnet? Du speicherst ja Einsatznummern, Fahrzeuge und Besatzungen. Das sind teils persönliche Daten also muss der Zugriff geregelt sein!
  3. Datensicherheit und Redundanz - auch wenn es nur ein Hobbyprojekt ist, irgendwann verlässt sich jemand auf deine Daten. Und wenn aufgrund eines fehlenden Datensatzes die Abrechnung nicht funktioniert - wer muss seinen Kopf dafür hinhalten? Auch bei den Lebensrettern gehts letztendlich nur ums Geld - welches die Leitzentralen idR. nicht haben.

Als Stundensatz würde ich 45 - 75 Euro (zzgl. 19%) für gerechtfertigt halten. Hängt ein bisschen von deiner Erfahrung ab. Da das Projekt allerdings schon fertig ist nimm Tagessätze - die Stunden kannst Du wahrscheinlich eh nicht mehr genau nachweisen. Ja nach Erfahrung wären 300 - 500 Euro gerechtfertigt. Klär das ganze aber mit deinem Steuerberater!!! Mach dich im Zweifelsfalle auf eine saftige Umsatzsteuernachforderung gefasst!

Falls es nach dem Motto läuft: Ach das passt alles schon, Pflichten- und Lastenheft brauchen wir nicht und es hat eh nur der Einsatzleiter Zugriff - lass Dir das unbedingt schriftlich geben!!! Einsatzleiter wechseln, Behördenleiter wechseln - und nachher weiss keiner mehr wofür das Geld ausgegeben wurde. Nur dein Name steht dann noch im Raum als Ansprechpartner - und das kann je nach Beamten sehr unangenehm werden.

Ich kann LaTino in seinem Punkten da nur recht geben. Versuch dich nun in Schadensbegrenzung. Im Umgang mit der öffentlichen Hand sollte man als Entwickler sehr vorsichtig sein - die haben meist die besseren Anwälte und den längeren Atem. Falls es Probleme bei der Klärung einzelner Zuständigkeiten (Wartung, Sicherheit, etc.) geben sollte wirst Du wohl oder übel in den sauren Apfel beissen müssen und das ganze als Testprojekt oder Proof-of-Concept ohne praktischen Einsatz darstellen müssen - am besten mit einem Splash Screen und einer farblich abgehobenen Statusleiste. Somit kannst Du die Haftung im Fehlerfalle wenigstens ein bisschen beschränken.

20.02.2009 - 10:58 Uhr

Ich bin seit dem Ende des Studiums (2003) selbständig - allerdings hatte ich während des Studiums die Möglichkeit Kontakte aufzubauen und somit für die ersten 2 Jahre auch gleich Aufträge. Ich würde im Moment nichts anderes wollen und habe den Weg damals gewählt um eben nicht in einer Entwicklunsgabteilung an ständig gleichen Problemstellungen zu versauern. Selbständigkeit ist geil - aber auch ein Fluch.
Rein finanziell ist der Unterschied nicht so riesig. Man muss ja immer daran denken, daß man bei einer Festanstellung eben nicht nur ein Gehalt sondern auch etliche andere Vergünstigungen (Urlaubsgeld, Bezahlung während Krankheit, Arbeitsmaterial, Fortbildungen, usw.) bekommt welche man als Selbständiger auch selbst finanzieren muss - und gerade die Schulungen sind nicht günstig.

IPro:

  • häufig wechselnde Aufträge, Auftraggeber und Arbeitsumfeld
  • "Routine" gibt es fast nicht
  • Man kommt herum. 😉
  • Man passt seine Arbeitszeit seinem Leben an - und nicht das Leben seiner Arbeitszeit
  • Man gilt meist als Spezialist (auch wenn das häufig nicht stimmt) - ist gut fürs Ego.
  • Man erweitert ständig seinen Horizont. Wenn man gestern noch lernte wie eine USV funktioniert lernt man heute wie Optiken hergestellt werden und morgen, welche Regeln es im Versicherungsgewerbe gibt.

Con:

  • 2 Wochen ohne Auftrag (oder Auftragsbestätigung) verlangen schonmal starke Nerven.
  • schwere, langwierige Krankheiten sollten nicht auftreten.
  • die Familie leidet darunter das man häufig (meist Wochenweise) nicht da ist.
  • Man unterhält sich manchmal häufiger mit Rezeptionisten als mit seiner eigenen Frau.
  • Egal wie gut man sich im jeweiligen Team integriert - man ist immer ein "Externer".
  • Man muss sich häufig "beweisen" damit der Auftraggeber nicht das Gefühl hat sein Geld zum Fenster rauszuwerfen.
  • Strukturiertes Arbeiten und gute Dokumentationsfähigkeit sind ein absolutes Muss.
  • Die Wünsche des Kunden haben immer vorrang - auch wenn die Vorstellungen veraltet sind oder Mehrarbeit bedeuten. Als Externer ist es schwer die Angestellten dazu zu bringen eingefahrene Wege mal zu verlassen.
  • Urlaub 6 Monate im vorraus zu planen ist (fast) unmöglich.
  • kurze Wochenenden - die Buchhaltung muss man ja auch noch machen.

Wichtig als Selbständiger ist das Lösungs- und nicht das Problemorientierte Arbeiten. Man hat nicht die Zeit während des Projektes viele verschiedene Wege auszuprobieren und dann den optimalen zu wählen. Der Kunde erwartet 1 bis 2 Ansätze, die funktionieren und in der angegebenen Zeit umsetzbar sind. Wie eine Applikation funktioniert ist egal - aber sie muss ohne Einschränkungen funktionieren. Nebenbei sollte man eine gute Rechtsschutz und Haftpflicht haben. Ersteres für die eigenen Fehler - letzteres für "spezielle" Kunden.
Und im Moment fast wichtiger als Kundenkontakte sind Kontakte zu Vermittlern - klar kriegen die Ihren Obulus. Aber sie kümmern sich auch darum das Du ausgelastet bis und Du musst nicht "Klinkenputzen".

19.02.2009 - 18:33 Uhr

Hmm, ich arbeite hier mit Bildern von 8000x8000 Pixel (16Bit Tiefe) - eine OutOfMemoryException krieg ich erst ab dem 10. Bild (bei 2 GByte Ram) - kann es sein, daß deine laufenden Applikationen zuviel Speicher fressen oder du den Speicher an anderer Steller verbrätst?

19.02.2009 - 18:25 Uhr

Hmm, mag sein das ich da wieder zu einfach denke - aber machs doch einfach via Enum:


public enum AllowDoubleTypes
{
OnlyPositive,
OnlyNegative
// ... usw.
}

private AllowDoubleTypes _allowDouble = AllowDoubleTypes.OnlyPositive

public AllowDoubleTypes AllowDouble{ get { return _allowDouble; } set { _allowDouble = value; }}

Der Designer zeigt es dann schon richtig an - um die Behandlung dieser Property musst Du dich dann selbst kümmern. Oder habe ich da was missverstanden ...