Eine Klasse.
Ich hab mein Problem lösen können; war mein Fehler.
Zum ersten habe ich ein "WorkingObj" und eine "ObjList" und den Fehler gemacht, dass das WorkingObj eine DeepCopy bekommt und dann erst die ObjList, wodurch das betreffende WorkingObj ein anderes war, als das ensprechende in der ObjList.
Ich muss zuerst die Liste mit DeepCopies füllen und dann ein Objekt daraus an das WorkingObj übergeben...
Zum zweiten habe ich nicht beachtet, dass in der Name-Property des Objekts erst das Event ausgelöst wird, und danach erst der neue Wert gesetzt wird (damit ich noch den alten Wert ins Event übergeben kann).
Dadurch konnte die Änderung in der Liste in Dialog A allerdings erst nach dem ausgelösten Event geändert werden. Habe das Debugging allerdings immer vorher abgebrochen, bzw. nicht weiterverfolgt, da ich einen Fehler gesehen habe...
Sorry für den Thread.
grüße
Hallo herbivore,
Danke für die Antwort. Es geht nicht um die View.
Ich habe mir den Vorgang im Debug-Modus angeschaut:
Dialog A übergibt beim Doppelklick das Objekt mit einer Zuweisung (s.o.).
Nach der Änderung und dem Klick auf den OK-Button von Dialog B, wird z.b. der Name des Objektes geändert und Dialog A bemerkt dies, da es sich das entsprechende Event registriert hat. Und an dieser Stelle wird die ListView aktualisiert.
Aber in der "DeepCopy" in Dialog A, die ich vom Ausgangs-Form habe und die an das Dialog B übergeben wurde, welches das Objekt manipuliert hat, wurde nichts geändert.
1. Dialog_A.List[Obj1, Obj2, Obj3];
2. forall(Obj in Dialog A.List)
Obj.NameChanged += NameOfObjChanged;
3. Dialog_B.Obj = Dialog_A.List[1];
4. Dialog_B.Obj.Name = "neuer Name";
5. Dialog_A.NameOfObjChanged(...){
//Änderung des Namen registriert
//ListView aktualisieren
}
6. Dialog_A.List[1].Name ?= "alter name";
Ich hoffe, damit ist das Problem etwas verständlicher geworden.
grüße
Hallo Freunde,
entweder werde ich verrückt oder ich verstehe das Referenzmodell von C# nicht ganz.
Ich habe ein Programm indem Konfiguration-Daten über ein Dialog A bearbeitet werden können.
Die Daten werden als DeepCopy() an das Dialog A übergeben, damit ich beim "Abbrechen" der Bearbeitung keine Arbeit habe alles wieder umzubiegen. (Modell BusinessObjekt)
In dem Dialog A werden die Daten in einer Tabelle angezeigt, per Doppelklick kann man nun ein spezielles Objekt in einem weiteren Dialog B bearbeiten, dabei wird das Objekt mit
Dialog_B.Objekt = Dialog_B.List[X]
übergeben.
Weiterhin habe ich in Dialog A die Events der Objekte registriert, um auf Änderungen des Models in der View zu reagieren.
Ändert nun Dialog_B die Daten vom übergebenen Objekt, so wird der EventHandler korrekt ausgeführt, aber die Daten in der Liste von Dialog A wurden NICHT geändert.
Sollte ich das Objekt mit ref üdergeben (ist mir gerade eingefallen und werde ich gleich testen).
Wenn ja warum, ich dachte, es werden immer Referenzen bei ReferenzObjekten übergeben und keine Kopien.
Grüße
Mario
Leider auch nicht, verschiedene Benennung führt zu den selben Fehlern.
Edit: ok hab meinen Fehler gefunden hatte eine endlod-scheife erzeugt -_-'
folgender Fehler taucht nun auf.
Kann mir einer die Hinweise erklären, die vom Compiler geworfen werden?
Fehlermeldung:
Fehler beim Deserialisieren von Parameter http://www.qpulse.com/QPulseWebServices/v1.2/:newOccurrence. Die InnerException-Nachricht war "Der Typ 'DataField2' mit dem Datenvertragsnamen 'Occurrence: http://www.qpulse.com/QPulseWebServices/v1.2/' wird nicht erwartet. Verwenden Sie ggf. einen DataContractResolver, oder fügen Sie alle unbekannten Typen statisch der Liste der bekannten Typen hinzu, beispielsweise mithilfe des KnownTypeAttribute-Attributs oder indem Sie sie zur Liste der bekannten Typen hinzufügen, die an DataContractSerializer übergeben wird.". Weitere Details finden Sie unter "InnerException".Server stack trace:
bei System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart (XmlDictionaryWriter writer, PartInfo part, Object graph)
bei System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter (XmlDictionaryWriter writer, PartInfo part, Object graph)
bei System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameters (XmlDictionaryWriter writer, PartInfo[] parts, Object[] parameters)
bei System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody (XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
bei System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents (XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
bei System.ServiceModel.Dispatcher.OperationFormatter. OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents (XmlDictionaryWriter writer)
bei System.ServiceModel.Channels.BodyWriter.WriteBodyContents (XmlDictionaryWriter writer)
bei System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents (XmlDictionaryWriter writer)
bei System.ServiceModel.Channels.Message.OnWriteMessage (XmlDictionaryWriter writer)
bei System.ServiceModel.Channels.Message.WriteMessage (XmlDictionaryWriter writer)
bei System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage (Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
bei System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage (Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
bei System.ServiceModel.Channels.MessageEncoder.WriteMessage (Message message, Int32 maxMessageSize, BufferManager bufferManager)
bei System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage (Message message)
bei System.ServiceModel.Channels.HttpOutput.Send (TimeSpan timeout)
bei System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.SendRequest (Message message, TimeSpan timeout)
bei System.ServiceModel.Channels.RequestChannel.Request (Message message, TimeSpan timeout)
bei System.ServiceModel.Dispatcher.RequestChannelBinder.Request (Message message, TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.Call (String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.Call (String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
bei System.ServiceModel.Channels.ServiceChannelProxy.InvokeService (IMethodCallMessage methodCall, ProxyOperationRuntime operation)
bei System.ServiceModel.Channels.ServiceChannelProxy.Invoke (IMessage message)Exception rethrown at [0]:
bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage (IMessage reqMsg, IMessage retMsg)
bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke (MessageData& msgData, Int32 type)
bei QPulse_01.QPulseWebServices.Occurrence.IOccurrence.CreateNewOccurrence (CreateNewOccurrenceRequest request)
bei QPulse_01.QPulseWebServices.Occurrence.OccurrenceClient.CreateNewOccurrence (CreateNewOccurrenceRequest request) in .........\Reference.cs:Zeile 3363.
bei Programm.Main (String[] argv) in .........:Zeile 150.++++++++++++++++++++++++++++++
InnerException:
Der Typ 'DataField2' mit dem Datenvertragsnamen 'Occurrence: ht****tp://www.qpulse.com/QPulseWebServices/v1.2/' wird nicht erwartet. Verwenden Sie ggf. einen DataContractResolver, oder fügen Sie alle unbekannten Typen statisch der Liste der bekannten Typen hinzu, beispielsweise mithilfe des KnownTypeAttribute-Attributs oder indem Sie sie zur Liste der bekannten Typen hinzufügen, die an DataContractSerializer übergeben wird.
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType (DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType (XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize (XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
bei WriteArrayOfDataFieldToXml (XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
bei System.Runtime.Serialization.CollectionDataContract.WriteXmlValue (XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue (DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType (DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize (XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference (XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
bei WriteOccurrenceToXml (XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
bei System.Runtime.Serialization.ClassDataContract.WriteXmlValue (XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue (DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
bei System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType (DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
bei System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent (XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
bei System.Runtime.Serialization.DataContractSerializer.InternalWriteObject (XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
bei System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions (XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
bei System.Runtime.Serialization.XmlObjectSerializer.WriteObject (XmlDictionaryWriter writer, Object graph)
bei System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart (XmlDictionaryWriter writer, PartInfo part, Object graph)
OK, hab ich soweit verstanden und scheint auch soweit zu klappen, aber es hat sich noch ein weiteres Problem ergeben, evtl. könnt ihr mir da aber garnicht helfen.
Ich habe ein Objekt A, welches ein Array besagter Klasse DataField beinhaltet.
Wenn ich nun meine neue Liste mit der erweiterten Version DataField2 erstellt habe und an Object A hänge, funktioniert noch alles wunderbar.
Wenn ich im Debug-Modus mir nun die Liste ansehen, ist der "ForeignKey" mit einem roten Ausrufezeichen versehen mit der Beschreibung: "ForeignKey = Die Funktionsauswertung wurde abgebrochen." (An dieser Stelle steht normalerweise der zugewiesene Wert)
Weiterhin, bekomme ich, wenn ich das Objekt per Webservice übermittle eine StackOverflowException.
grüße
Ani
PS: Habe die Klasse wie folgt erweitert:
[DataContract(Name = "DataField", Namespace = "NamespaceXYZ")]
class DataField2 : DataField{
[DataMember]
public string fk;
Public string FK{ get; set; }
}
Wenn ich wie folgt erweitere, kann ich meine Version2 Liste nicht der Liste von Objekt A zuweisen (da ja keine Verbindung existiert)
[DataContract(Name = "DataField", Namespace = "NamespaceXYZ")]
class DataField2 : IExtensibleDataObject{
[DataMember]
public string fk;
Public string FK{ get; set; }
//Alle Properties und Attribute vom Original übernommen
}
@Abt Danke für die Antwort.
Die Klasse DataField wird bereits von dem WebService implementiert und existiert (praktisch Version 1)
Nun möchte ich gern eine Version 2, indem ein ForeignKey (FK) Feld dazukommt.
Dazu muss ich doch eigentlich nur folgendes schreiben:
[DataContract(Name = "DataField", Namespace = "NamespaceXYZ")]
class DataField : IExtensibleDataObject {
[DataMember]
public string fk;
private ExtensionDataObject data;
public ExtensionDataObject ExtensionData {
get { return data; }
set { data = value; }
}
}
Aber beim erstellen eines DataField sehe ich nun nur das .fk field und die ExtensionData Property.
Eigentlich müsste ich doch aber alle Properties von Version 1 plus mein fk sehen, oder?
gruß
ani
Hallo Leute,
ich nutze einen WebService, der bei uns auf dem Server im Keller läuft.
Eine Klasse DataField implementiert das IExtensibleDataObject:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="DataField", Namespace="NamespaceXYZ")]
[System.SerializableAttribute()]
public partial class DataField : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {...}
Wenn ich das richtig verstanden habe, kann ich mittels des Interfaces nun die DataField-Klasse um eine gewünschte Property "ForeignKey" erweitern:
[DataContract(Name = "DataField", Namespace = "NamespaceXYZ")]
class DataField : IExtensibleDataObject {
[DataMember)]
public string FK { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
Aber vermutliche habe ich die nutzung des ganzen nicht richtig verstanden oder angewendet, wenn wenn ich nun ein DataField anlege, ist darin nur der ForeignKey und das ExtensionDataObject enthalten und nicht die restlichen Properties ebenfalls...
folgende Links habe ich genutzt:
Dynamic -VAR
IExtensibleDataObject-Schnittstelle
MfG
Ani
OK, für den Render-Bereich ist mir nun klar, einfach das entsprechende Rechteck nur Zeichnen, den Rest ignorieren.
Für den Ladevorgang, bzw Update Vorgang heißt das was:
Die Bewegung soll eigentlich frei sein.
Das mit den Layern klingt gut, wie realisiert sich das genau?
Ich hab aktuell mit den Objekten so gedacht:
Alle Objekte in einer Liste, welche bei jedem Render-Cycle durchgegangen wird und einen Draw für jedes Ojekt ausführt.
Layer würde ja heißen das ich entweder mehrere Listen habe, die einfach nur eine bestimmte Reihenfolge haben:
foreach(Mesh m in Background) m.Draw(...);
foreach(Mesh m in Objects) m.Draw(...);
foreach(Mesh m in Player) m.Draw(...);
foreach(Mesh m in Foreground) m.Draw(...);
foreach(Mesh m in Text) m.Draw(...);
foreach(Mesh m in UI) m.Draw(...);
oder die Objekte sind einfach in einer Liste entsprechend sortiert. Abe rich denke eine Trennung wäre da einfacher
Im Prinzip würde ich Tiles im Kachelmuster schon schön finden (oder gibt es noch eine bessere variante das umzusetzen?).
Ich dachte an soetwas wie: Player ist z.b. 30x30 Groß und ein Tile 5x5 (für Boden, Sand Wasser z.b.), um eine feinere Struktur zu bekommen.
Objekte etc. wären halt größer.
Dinge wie Wolken könnte man als pngs ja einfach "drüber schweben" lassen.
Womit ich glaube das grüßte Problem habe, ist die Karte nur teilweise zu laden. Also ich muss ja nur meinen aktuellen "Viewport" zeichnen und icht alles was es gibt.
Jedes Tile müsste dann ja trotzdem eine entsprechende Graphik laden...
Hallo Freunde,
ich versuche mich aktuell an Game-Development mit GDI+, um mich etwas an das Thea heran zu tasten.
Es soll ein 2D-Old-School-Single-Player-Mini-RPG werden. ^^
Ich hab aktuell einen TickBasierten Game-Cycle und die Basis-Klassen für meine Game-Objekte. (Bitmap sprite, Point pos, Size size, ..., so etwas)
Nun soll es an die Weltkarte gehen und ich frage mich, ob ich eine Karte als Bitmap mache und die nach Bewegung des Helden einfach verschiebe, oder ob ich lieber ein Array mit Cells und Tile-Informationen machen soll.
Bei der Bitmap-Variante müsste ich natürlich noch Objecke, wie Berge, extra auf der Map plazieren. Bei der Array-Variante könnte ich diese direkt in die Tile-Information mit reinschreiben, bzw erkennen.
Was ist besser, schlechter oder lauf ich komplett in die falsche Richtung?
gruß
ani
Hallo Leute,
ich habe eine Oberfläche, die eine feste Größe hat ( 80% des Bildschirm in Höhe und Breite [das Programm läuft Fullscreen]).
An dieses Programm kann per eMail eine Nachricht geschickt werden, welche dann auf der Oberfläche angezeigt werden soll.
Je nach länge der Nachricht muss ich nun die Schriftgröße skalieren, leider habe ich im Netz nichts ordentliches gefunden und bisher auch keine gute Idee gehabt.
Ich hatte versucht über TextMeasure die benötigte Größe rauszufinden, aber leider wird diese "einzeilig" berechnet, also nur die Höhe der Buchstaben wird ermittelt... und nicht einer Box.
Gruß
Ani
Also anstatt der 3 PictureBoxen habe ich eine kleine strukture genommen, welche nur das bild, sowie left und width.
Es flackert nicht mehr an den Rändern und ist auch nicht langsam oder sonst irgendwas, das einzige ist, dass es leiche ruckler zwischendurch gibt. Es ist ein bischen schwer zu beschreiben, deswegen bin ich mal so frei und poste nochmal den gesamten Code für die Klasse.
public class alGallery : Control {
private struct imgBox {
public int left;
public int width;
public Image img;
public void draw(Graphics g) {
g.DrawImage(img, new Rectangle(new Point(left, 0), new Size(width, (int)g.ClipBounds.Height)));
}
}
private Queue<Image> imgList;
private int imgCount;
private bool bInitImages;
private Timer timerSliding;
private imgBox imgBox1;
private imgBox imgBox2;
private imgBox imgBox3;
int mitte;
public Queue<Image> ImageList { get { return imgList; } }
public alGallery() {
init();
}
public alGallery(Queue<Image> imgList) {
this.imgList = imgList;
}
private void init() {
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
imgList = new Queue<Image>();
timerSliding = new Timer();
timerSliding.Interval = 10;
timerSliding.Tick += new EventHandler(timerSliding_Tick);
sf = new StringFormat();
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Far;
}
private void timerSliding_Tick(object sender, EventArgs e) {
if (imgCount > 2) {
imgBox1.left++;
imgBox2.left++;
imgBox3.left++;
if (imgBox1.left > this.Width) resfreshPictureBox(ref imgBox1, imgBox2);
if (imgBox2.left > this.Width) resfreshPictureBox(ref imgBox2, imgBox3);
if (imgBox3.left > this.Width) resfreshPictureBox(ref imgBox3, imgBox1);
Invalidate();
}
}
public void initImages(bool force) {
if (!bInitImages || (bInitImages && force)) {
mitte = (int)(this.Width * 0.6);
imgCount = imgList.Count;
if (imgCount > 2) {
imgBox1 = new imgBox();
imgBox1.img = imgList.Dequeue();
imgBox2 = new imgBox();
imgBox2.img = imgList.Dequeue();
imgBox3 = new imgBox();
imgBox3.img = imgList.Dequeue();
imgBox1.width = imgBox1.img.Width;
imgBox2.width = imgBox2.img.Width;
imgBox3.width = imgBox3.img.Width;
imgBox1.left = -imgBox1.width + links - 10;
imgBox2.left = links;
imgBox3.left = links + mitte + 10;
} else if (imgCount > 0) {
imgBox1 = new imgBox();
imgBox1.img = imgList.Dequeue();
imgList.Enqueue(imgBox1.img);
imgBox1.width = this.Size.Width;
}
bInitImages = true;
}
}
public void stopPerformance() {
timerSliding.Stop();
}
public void startPerformance() {
timerSliding.Start();
}
private void resfreshPictureBox(ref imgBox imgBox, imgBox to) {
imgList.Enqueue(imgBox.img);
imgBox.img = imgList.Dequeue();
imgBox.width = imgBox.img.Width;
imgBox.left = to.left - imgBox.width - 10;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
imgBox1.draw(e.Graphics);
imgBox2.draw(e.Graphics);
imgBox3.draw(e.Graphics);
}
}
Meine Vermutung ist, dass die aktualisierungsrate (aller 10 Millisekunden) zu viel für die CPU ist?! Aber bei Höheren oder auch geringeren Raten kommt es zu diesen "rucklern" (die echt minimal sind, aber dem Auge doch auffallen)
grüße
Ani
@Herbivore, ich hab mit alle Links zu dem Thema durchgelesen und soweit ich konnte, bzw es sinn machte auch umgesetzt. Es ist auch weniger ein echtes Flackern.
Fester Wert, da ich die Größe des Ferhnsehers weis und somit auch die Abmaße für die SlideShow festlegen kann ohne eine dynamische größe berechnen zu müssen.
OK, die PictureBox hatte ich genommen, um das Bild automatrisch nach-Scalieren zu lassen, aber das hat sich ja nun erübrigt. Ich werde die Bilder mal selbst zeichnen, mal sehn ob es dann besser ist 😃
Danke.
Danke für eure Antworten.
Die pictureBoxen haben eine Breite von 1105x aber ich hatte den Mode auf ScaleImage gesetzt, damit auch höhe gleich ist.
Hab es jetzt geändert, mit einem Scaling VOR dem aufbau jedweder Form/PictureBoxen... auf eine feste größe und den Mode auf CenterImage.
Das verlangsamen ist nun komplett weg, alle Bilder bewegen sich gleich schnell, nur flackern die Ränder der PictureBoxen ein ganz klein wenig (also echt nur 2 pixel oder so am rand). Es ist wenig, aber man sieht es. ich befürchte dass ich dies nicht wegbekomme ohne DirectX oder XNA oder so was, oder?
Das Konzept mit den Pipline ist sehr interessant und aber ich ganz treffend für mich (dnek ich), da ich die Bilder ja schon or dem Anzeigen lange bearbeitet habe.
grüße
Ani
Hallo,
danke für eure Antworten...
OK etwas Hintergrund zu dem Programm.
Es läuft auf einem Rechner der im Essbereich steht und mit einem großen Monitor verbunden ist.
Unsere Sekretärin soll die Möglichkeit haben auf ein Vordefiniertes Netzlaufwerk Bilder hochzuladen und dann eine eMail an den Benutzer (für das Programm) schicken, dass eine neue Gallerie mit den und den Parametern zur Verfügung steht.
Das Programm liest die Parameter der eMail, zieht sich die Bilder auf die Platte (damit die Gallerie erhalten bleibt, auch wenn eine neue erstellt wird), skaliert die Bilder und zeigt die aktuelle Gallerie an.
@dN!3L, Optimierung ist vll das falsche Wort, ich möchte mein Problem aus der Welt schaffen, dass bei ehemals großen Bildern, der Slide trotzdem langsamer wird und leicht (an den Rändern) flackert.
@MrSparkle, ich skaliere die Bilder nur einmal:
Das Programm liest die Bilder ein, skaliert diese auf eine feste Breite und speichert sie dann komprimiert auf der lokalen Platte ab. Danach werden die Bilder nicht mehr skaliert. Oder verstehe ich dich falsch?
grüße
ani
Hallo Leute,
ich habe ein Control "alGallery", welches, wie der Name sagt, eine Gallerie ist.
Diese greift auf eine Liste von Bilder zu, welche zuvor geladen, auf die richtige Größe angepasst und mittels JPEG komprimiert wurden, so dass die Bilder eine Breite von 1105px haben eine größe von 100 bis 500 KB.
Einige der Bilder waren vorher kleiner (Auflösung) und andere hatte eine Auflösung von so 3000x oder 4000x.
Die Gallerie soll eine SlideShow sein, also es werden immer 3 Bilder angezeigt (eins voll, die anderen halb) und das ganze läuft dann von links nach rechts durch. Ist ein Bild rechts "aus dem Bildschirm gelaufen", wird das nächste geladen und es landet wieder links.
Die alGallery ist erbt von Control und die Bilder sind in einer PictureBox (gesamt 3 auf der alGallery).
Der Slide funktionert gut und bei den Bildern mit geringer Auflösung auch flüssig, nur die Bilder, welche vorher eine sehr hohe Auflösung hatten, bei denen wird der Slide langsamer und es flackert leicht.
Auf dem alGallery Control ist DoubleBuffer an, sowie AllPaintingInWmPaint und OptimizedDoubleBuffer.
Hättet ihr evtl. noch ein paar Tips zum optimieren?
PS: Auf die Bilder habe ich keinen Einfluss, da diese von einem Netzlaufwerk kommen und die werden immer mal geändert, neue hochgeladen, gelöscht, ...
Also kann ich sie nicht vorher schon bearbeiten.
Zum Schluss noch etwas Code:
Resize:
public static Image ResizePicByWidth(Image sourceImage, double newWidth) {
double sizeFactor = newWidth / sourceImage.Width;
double newHeigth = sizeFactor * sourceImage.Height;
Bitmap newImage = new Bitmap((int)newWidth, (int)newHeigth, PixelFormat.Format24bppRgb);
newImage.SetResolution(sourceImage.HorizontalResolution,
sourceImage.VerticalResolution);
using (Graphics g = Graphics.FromImage(newImage)) {
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(sourceImage, new Rectangle(0, 0, (int)newWidth, (int)newHeigth));
}
return newImage;
}
Komprimieren:
public static void JpegBildKomprimieren(Image quellBild, int qualitaet, string speicherPfad) {
try {
//Ein ImageCodecInfo-Objekt für den JPEG-Codec anlegen
ImageCodecInfo jpegCodec = null;
//Den Qualitätsarameter konfigurieren (Qualitätsfaktor in
//Prozent angeben)
EncoderParameter qualitaetsParameter = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, qualitaet);
//Alle im System verfügbaren Codecs auflisten
ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders();
EncoderParameters codecParameter = new EncoderParameters(1);
codecParameter.Param[0] = qualitaetsParameter;
//Den JPEG-Codec unter allen Codecs finden und dem
//Codec-Info-Objekt zuweisen
for (int i = 0; i < alleCodecs.Length; i++) {
if (alleCodecs[i].MimeType == "image/jpeg") {
jpegCodec = alleCodecs[i];
break;
}
}
//Das Bild abspeichern
quellBild.Save(speicherPfad, jpegCodec, codecParameter);
} catch (Exception e) {
throw e;
}
}
alGallery (ausschnitte)
public class alGallery : Control {
private Queue<Image> imgList;
private bool bInitImages;
private Timer timerSliding;
private PictureBox imgBox1;
private PictureBox imgBox2;
private PictureBox imgBox3;
StringFormat sf = new StringFormat();
int links;
int mitte;
int rechts;
public Queue<Image> ImageList { get { return imgList; } }
public alGallery() {
init();
}
public alGallery(Queue<Image> imgList) {
this.imgList = imgList;
}
private void init() {
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
imgList = new Queue<Image>();
timerSliding = new Timer();
timerSliding.Interval = 10;
timerSliding.Tick += new EventHandler(timerSliding_Tick);
timerSliding.Start();
sf = new StringFormat();
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Far;
}
private void timerSliding_Tick(object sender, EventArgs e) {
if (imgList.Count > 2) {
imgBox1.Left+=2;
imgBox2.Left+=2;
imgBox3.Left+=2;
if (imgBox1.Left > this.Width) resfreshPictureBox(imgBox1, imgBox2);
if (imgBox2.Left > this.Width) resfreshPictureBox(imgBox2, imgBox3);
if (imgBox3.Left > this.Width) resfreshPictureBox(imgBox3, imgBox1);
}
}
public void initImages(bool force) {
if (!bInitImages || (bInitImages && force)) {
links = (int)(this.Width * 0.2);
mitte = (int)(this.Width * 0.6);
rechts = (int)(this.Width * 0.2);
if (imgList.Count > 2) {
imgBox1 = new PictureBox();
imgBox1.SizeMode = PictureBoxSizeMode.StretchImage;
imgBox1.Image = imgList.Dequeue();
imgBox1.Parent = this;
imgBox2 = new PictureBox();
imgBox2.SizeMode = PictureBoxSizeMode.StretchImage;
imgBox2.Image = imgList.Dequeue();
imgBox2.Parent = this;
imgBox3 = new PictureBox();
imgBox3.SizeMode = PictureBoxSizeMode.StretchImage;
imgBox3.Image = imgList.Dequeue();
imgBox3.Parent = this;
imgBox1.Width = imgBox2.Width = imgBox3.Width = mitte;
imgBox1.Height = imgBox2.Height = imgBox3.Height = this.Height;
imgBox1.Left = -imgBox1.Width + links - 10;
imgBox2.Left = links;
imgBox3.Left = links + mitte + 10;
} else if (imgList.Count > 0) {
...
}
bInitImages = true;
}
}
private void resfreshPictureBox(PictureBox imgBox, PictureBox to) {
imgList.Enqueue(imgBox.Image);
imgBox.Image = imgList.Dequeue();
imgBox.Left = to.Left - imgBox.Width - 10;
}
}
danke schön für den link, funktioniert so...
Der folgelink in dem thread ist auch sehr interessant. Der erklärt warum es so geht.
grüße
ani
Danke für die antworten...
Wenn ich nur Load verwende, gibt es auch eine Fehlermeldung, ob Zwischenspeicher über WebClient, oder direkt. Wenn ich die temporäre Datei mit dem utf-8 encode manuell versehe, dann funktioniert es. Nur möchte ich ja, dass das Programm aller 10 Sekunden die Wetterdaten abfragt und aktuallisiert.
Zwischenlösung, die mir einfällt, wäre das ganze als Textdatei zu öffnen und per StreamWriter zu bearbeiten und dann erst als XML zu öffnen?! Wirkt mir etwas umständlich dafür, dass es eine automatisch generierte XML-Datei von Google ist. 😦
grüße
ani
Natürlich habe ich mir den XML-Code angesehen und er ist völlig komform.
hier ein Ausschnitt:
<?xml version="1.0"?>
<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" >
<forecast_information><city data="Schkeuditz, Sachsen"/>
<postal_code data="04435-Germany"/>
<latitude_e6 data=""/>
<longitude_e6 data=""/>
<forecast_date data="2012-08-20"/>
<current_date_time data="1970-01-01 00:00:00 +0000"/>
<unit_system data="SI"/>
</forecast_information>
<current_conditions>
<condition data="Klar"/>
<temp_f data="97"/>
<temp_c data="36"/>
...
Hallo leute,
ich hab mit über die Wetter api von google, eine xml datei gezogen:
http://www.google.com/ig/api?weather=04435-Germany&hl=de
Es ist ja anzunehmen, dass diese XML-Datei keine fehler ausweist.
Folgenderweise ist mein ablauf:
XmlDocument doc = new XmlDocument();
new System.Net.WebClient().DownloadFile("http://www.google.com/ig/api?weather=04435-Germany&hl=de", "temp.xml");
doc.LoadXml("temp.xml");
Leider kommt die Fehlermeldung > Fehlermeldung:
"Ungültige Daten auf Stammebene. Zeile 1, Position 1."
Wo könnte da der Fehler liegen?
grüße
ani
bin mit win32 api leier wenig bis ganz wenig vertraut 😄 wenn du gute quellen dazu weist wär das sicher hilfreich (ich weis google ist mein freund...)
ziel OS soll bis win7 sein...
hallo Leute,
wollt gern wissen, ob es möglich ist, die taskbar items, bzw die im tray befindlichen elemente irgendwie abzurufen, sodass man die informationen weiterverarbeiten kann...
Zweck soll ein Plugin für Samurize sein (falls euch das nix sagt: Samurize)
mfg
ani
Alles klar, sieht echt klasse aus...
ein letztes noch, kann man aus der Region einen GraphicPath bekommen?
mfg
ani
die idee mit den regions hat echt potential xD
Bin grad am lesen @herbivore (sorry ^^)
Der Spalt soll "frei" sein, also dass man sieht, was drunter ist...
hallo winSharp93,
kannst du das mit den Regions bitte näher erklären?
Mit welcher Funktion zeichne ich solche schwarzen Bögen, wollt ich wissen...
hab probleme das mit "DrawArc" umzusetzten...
ah stimmt, mathe für anfänger xD
jetzt hab ich alle punkte ...
mit linien sieht es wie folgt aus, wie mach ich jetzt, dass es schöne kurven werden, anstelle von den linien?
wäre trick 17 xD
soll aber eine Lücke da sein..., so wie in Abb 2.
hab noch ein wenig probiert und bekomme bei folgendem Algorithmus anhängendes Bild
float BubleSize = 60.0f;
PointF pMitte = new PointF((recEllipse.Width - 2) / 2, (recEllipse.Height - 2) / 2);
float fX1, fY1;
PointF pXY1;
int anz = 5;
float phi = 360.0f / anz;
float radius = recEllipse.Width * 0.45f;
for(int i = 0; i < anz; i++) {
float alpha = (float)((phi * i) * Math.PI / 180) - (float)Math.PI * 0.5f;
fX1 = (float)(Math.Cos(alpha) * radius);
fY1 = (float)(Math.Sin(alpha) * radius);
pXY1 = new PointF(pMitte.X + fX1, pMitte.Y + fY1);
RectangleF rec = new RectangleF(recWheelDraw.X + pXY1.X - BubleSize / 2, recWheelDraw.Y + pXY1.Y - BubleSize / 2, BubleSize, BubleSize);
gpWheel.AddEllipse(rec);
double deg = WheelHelper.ToDegree(alpha) + 90.0f;
gpWheel2.AddArc(new RectangleF(recWheelDraw.X + pXY1.X - BubleSize / 2, recWheelDraw.Y + pXY1.Y - BubleSize / 2, BubleSize, BubleSize), (float)deg, 180);
}
Wie bekomm ich jetzt die Koordinaten für die Anfang- und Endpunkte der Halbkreise raus?
mfg
ani
PS: die linien Zeichnen sich selber...
Hallo Leute,
ich bin dabei, ein neues Control zu schreiben, welches die Standard Minimieren-, Maximieren-, Schließen-Buttons ersetzten soll, im Bild sieht man das fast fertige Control (Abb. 1).
Leider fehlt noch ein optisches Detail, welches in Abb. 2 zu erkennen ist. Der Kreis, um den die Buttons plaziert werden, soll "eingeschnitten" sein.
die Berechnung der Plazierung erfolgt dynamisch je nach Anzahl der Buttons...
Mein Problem ist nun, diese "eingeschnittenen" Kreise zu zeichnen.
Ich hab ein wenig mit Arcs, Curves und Beziers experimentiert, aber komme nicht richtig weiter...
Könnte mir vll einer erklären (mit Beispielen wäre schön), die man die drei richtig benutzt, um so ein Objekt zu erhalten?
mfg
Ani
sorry, hab das prohekt einn bissl ruhn lassen müssen, war krank 😦(
habs geschafft, dass wenn ich die maus nach rechts ziehe, das ganze schön selektiert wird (zittert zwar alles, aber das prob lös ich später ^^)
weis nur nicht ganz, wie ich es realisieren soll, damit die buchstaben auch markiert werden, wenn ich nach links ziehe...
PS: die ganze "ich bastln mir meine eigene textbox"-sache is schwerer als gedacht 😦
edit:
hab die vorgehnsweise vergessen xD:
bei MouseDown wird die position gemerkt (also bei welchem char-index wir sind) ("firstChar") und bei MouseMove jeweils welche weiterhin markiert werden ("lastChar") und am ende von MouseMove werden alle buchsten von "firstChar" bis "lastChar" markiert.
Hallo leute...
Da ich den umgang beim Design der Standard TextBox leid bin, wollte ich meine eigene schreibe:
Jedoch hat sich die Sache in bestimmten Pukten komplexter ergeben als gedacht 😦
Was funktioniert:
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
und über
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if(m.Msg == (int)WM_COMMANDS.WM_PAINT) { ...}
Mein momentanes Hauptproblem ist es, einen gewünschten Text per Maus zu selektieren...
Folgendes:
Meine Zeichen sind sogenannte 'TextChar':
public class TextChar: IDisposable {
private static int counter;
private int id;
private int index;
private int left;
private int charWidth;
private bool selected;
private char key;
public TextChar(char key, bool selected) {
this.id = counter++;
this.key = key;
this.selected = selected;
}
public int ID { get { return id; } }
public int Index { get { return index; } internal set { index = value; } }
public char Key { get { return key; } set { key = value; } }
public int Left { get { return left; } set { left = value; } }
public int CharWidth { get { return charWidth; } set { left = value; } }
public bool Selected { get { return selected; } internal set { selected = value; } }
public void ReCalcCharWidth(Graphics g, Font font) {
//...
}
public void Dispose() {
//...
}
private Rectangle MeasureString(String strText, Font font, Graphics gDevice) {
//...
}
}
<-- Diese werden in einer Liste (
TextCharCollection : IList<TextChar>
) gespeichert un dann wie auch immer benutzt um zu zeichnen, text hinzuzufügen, zu selektieren, was auch immer.
Der BlinkerCursor is einfach nur ein index, welcher halt die aktuelle TextChar Position speichert und dann an der stelle gezeichnet wird...
protected override void OnMouseDown(MouseEventArgs e) {
//...
}
Hier wird der BlinkerIndex neuberechnet, abhängig von der Mausposition und anhand der 'Left' bzw. 'CharWidth' Propertie kann ein RecTangle erzeugt werden und geprüft werden, ob die Mouse da drin is...
protected override void OnMouseMove(MouseEventArgs e) {
//...
}
Hier sollte nun das eigentliche selektieren geschehen, un den BlinkerIndex neu zu setzen, klappt hier auch wunderbar, nur das Markieren des Textes will nicht wie ich:
if(mouseDown) {
mousePos = e.Location;
foreach(TextChar tc in myText) {
Rectangle recCheck = new Rectangle(tc.Left, 0, tc.CharWidth, this.Height);
if(recCheck.Contains(mousePos)) {
if(BlinkerIndex > -1 && BlinkerIndex + 1 < myText.Count) {
int mouseBlinkerDif = mousePos.X - (tc.Left + tc.CharWidth);
//bool left = new Rectangle(recCheck.X + (int)(recCheck.Width / 2), recCheck.Y, (int)(recCheck.Width / 2), recCheck.Height).Contains(mousePos);
Console.WriteLine("mousePos.X: " + mousePos.X);
Console.WriteLine("myText[tc.Index + 1].Left: " + myText[tc.Index + 1].Left);
bool go = mousePos.X >= myText[tc.Index + 1].Left - 3;
if(go) {
BlinkerIndex = tc.Index;
[B]tc.Selected = !tc.Selected;[/B]
} else { }
Console.WriteLine("Invalidate : OnMouseMove");
Invalidate(recBlinker);
break;
}
}
}
}
der text wird nur teilweise un lückenhaft selektiert, ...
mfg
ani
ok danke ihr beiden...
ich verareite die eingaben jetzt einfach per "ProcessCmdKey"
un wenn ich "return true" mach, wird der fokus auch nicht mehr weggegeben...
für alle die evtl das selbste problem hatten, sollten folgende zeit beachten, denn sonst geht der fokus mit "Tab" nicht mehr weiterzugeben:
//...
if(keyData == Keys.Tab) {
if(Parent!=null)
Parent.SelectNextControl(this, true, true, false, true);
}
//...
mfg
ani
ok, hab mal folgendes probiert:
zuerst hab ich alle key-handler von der form entfernt und die keyPreview=false gesetzt...
dann habe ich folgendes geschrieben:
protected override void OnKeyDown(KeyEventArgs e) {
e.Handled = true;
Console.WriteLine("OnKeyDown:\t" + e.KeyCode.ToString());
}
protected override void OnKeyPress(KeyPressEventArgs e) {
e.Handled = true;
Console.WriteLine("OnKeyPress:\t" + e.KeyChar.ToString());
}
protected override void OnKeyUp(KeyEventArgs e) {
e.Handled = true;
Console.WriteLine("OnKeyUp:\t" + e.KeyCode.ToString());
}
interessant ist, dass ich von allen drein KEINE ausgabe erhalte, wenn ich auf 'Pfeil-Links/Rechts' klicke, eine Ausgabe erhalte ich aber bei folgendem:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
Console.WriteLine("ProcessCmdKey:\t" + keyData.ToString());
return base.ProcessCmdKey(ref msg, keyData);
}
wie darf ich das verstehn?
ok also weder wenn ich alle verfügbaren key-events auf e.Handled = true setzte, noch wenn ichs auf die form ausweite, verhindert das defokusieren...
kannst du mir evtl. formal beschreiben, was ich in der wndProc abfangen un wie bearbeiten soll?
btw. sollte ich die verarbeitung der keys gleich mit in die wndProc übertragen oder lieber bei den standard evens belassen, also was glaubst du wäre optimaler?
hab festgestellt, dass es doch manchmal recht nervig ist zu unterscheiden, bzw rauszulesen, aus welchem event ich was verwenden soll...
mfg
ani
Hallo Herbivore,
die control verliert den focus noch immer 😦
edit: ich weis nicht ob es wichtig ist, aber das form wo das control drauf ist, hat die propertie 'KeyPreview = true'
Hallo leut...
ich bastel mir grade eine eigene TextBox und bin anscheint zu blöd, in selbiger zu navigieren...
Also ich meine per Pfeiltasten durch die Buchstaben zu huschen:
Immer wenn ich Pfeil-Links/Rechts drücke verliert mein Control den Fokus... kann man dies irgedwie abstellen?
sorry wenn die Frage zu banal is, aber ich find das echt grad nicht...
mfg
ani
danke für die antworten...
@Herbivore:
sieht echt nich so schön aus, außerdem wirkt das als "bild" n bissl künstlich, also die buchstaben...
@JAck30lena
hab mal mit TextRenderer.DrawText(...) versucht un siehe da, die buchstaben werdfen nicht mehr eingerückt xD sieht super aus ^^
ty again
mfg
ani
Hallo Leute,
beim Versuch meine eigene 'TextBox' zu schreiben (nicht von TextBox geerbt, sondern von UserControl) bin ich auf eine kleine Hürde gestoßen:
Hatte einige Probleme mit der korrekten Berechnung der Weite des Textes und habe hier auch einige Beiträge und Lösungen gefunden, folgende von 'Herbivore' habe ich verwendert:
MeasureString und Alternativen
Ich speichere die eingegebenen Chars in einer Liste, aus welcher sie dann beim zeichnen herausgelesen und vermessen werden...
Das Gute ist, zumindest theoretisch, da Herbivores Funktion die Minimalgrenzen berechnet, dass es keine Lücken geben sollte zwischen den Buchstaben...
Mein Problem ist nun, dass wie man im angehangenen Bild sieht, die Buchstaben nicht korrekt gezeichnet werden:
Die Graue Box ist die berechnete Fläche für die jeweiligen Chars, leider sind die etwas nach rechts verschoben.
Hab in meinem Code keinen Anlass für eine solche Differenz gefunden, daher frage ich mich, ob das evt mit der DrawString-Methode selbst zu tun hat? bzw dem übergebenen Rectangle...
PS: Die Pinkne Fläche ist selectierter Text...
mfg
Ani
öhm schon klar, wie kann man das beeinflussen? gibt da ja keine parameter oder so... (also bei der cos/sin-fkt)
sorry vll steh ich auch aufm schlauch
edit:
hab das bein vom schlauch genommen:
Bogenmaß = Winkel * PI/180
funktioniert jetzt super
danke nochma
also:
float fX, fY;
PointF pXY;
float phi = 360.0f / anzEcken;
for(int i = 1; i <= anzEcken; i++) {
float alpha = 45 - phi * i;
fX = (float)(Math.Cos(alpha) * fRadius3);
fY = (float)(Math.Sin(alpha) * fRadius3);
pXY = new PointF(pMitte2.X + fX, pMitte2.Y + fY);
g.DrawLine(new Pen(Color.Black, 1.0f), pMitte2, pXY);
}
so siehts jetzt aus, aber dabei komm angehängtes ergebnis bei raus...
die zahlen in den roten kreisen zeigen den reihenfolge, wie sie gezeichnet wurden (sicher ersichtlich ^^)
mfg
ani
hallo leute,
ich wollte, dass unter angabe von radius und anzahl der ecken, meine funktion ein n-eck zecihnet.
hab dann erstmal wieder mein TW rausgesucht und für die berechnung der x und y werte der spitzen folgende formel aufgestellt:
phi = 360/anzEcken;
x = cos(45 - phi) * radius
y = sin(45 - phi) * radius
bei der formel bin ich mir eigentlich auch ziemlich sicher, nur hab ich ein problem damit, eine for-schleife zu erstellen, die nun das n-eck zeichnet.
also wo in der formel, muss die zählvarialbe rein?
mfg
ani
ah ok, dann hab ich "BeginInvoke" immer falsch benutzt :<
abstürzen heißt, dass das panel weiß mit nem roten kreuz drinne wird. werd mir den artikel jetzt mal zu gemüte führen...
Feuer:
private void BrennTimer() {
Thread.Sleep(750);
Löschen();
}
private void Löschen() {
OnLöschen(this);
}
protected virtual void OnLöschen(Feuer feuer_) {
if(FeuerErlischt != null)
FeuerErlischt(this, new FeuerEventArgs(this));
}
Game:
f.FeuerErlischt += new Feuer.FeuerEventHandler(FeuerErlischt);
private void FeuerErlischt(object sender, Feuer.FeuerEventArgs e) {
lock(felderListe) {
int index = Game.GetSpecificObjectIndexFromList<Feuer>(felderListe[e.Feuer.Point], e.Feuer);
if(index >= 0) {
felderListe[e.Feuer.Point].RemoveAt(index);
//Wichtig:
OnUpdateGamePanel(e.Feuer.Point.X, e.Feuer.Point.Y, fieldSize, fieldSize);
}
}
}
GamePanel:
private void game_UpdateGamePanel(object sender, Game.UpdateGamePanelEventArgs e) {
lock(mutex)
//Wichtig:
BeginInvoke(new InvalidateAtEventHandler(InvalidateAt), e.X, e.Y, e.Width, e.Height, true);
}
Hey Leute,
ich programmiere z.Z. an nem Bomberman-Spiel auf Wunsch eines Freunden.
Zur Verwaltung der Spieldaten gibt es eine "Game" Klasse und eine "GamePanel"-Klasse, welches wie zu erwarten ein Panel ist und worauf das Spiel auch gezeichnet wird.
Alle relevanten Daten, wie Spieler, Feldobjekte, ect. liegen in "Game".
Tastatureingaben werden über "ProcessCmdKey" des MainForm abgefangen, an die "Game"-Klasse übergeben und dort verarbeitet (betreffende Figur wird bewegt, legt eine bombe...) der Invalidate(), um die Änderung auch sichtbar zu machen, wird über ein Event, welches von "GamePanel" registriert wird, ausgelöst.
Beispiel:
Spieler drückt Leertaste und setzt damit eine Bombe ab:
ProcessCmdKey() bemerkt, dass die Leertaste gedrückt wurde und meldet dies "Game".
"Game" ermittelt welcher Spieler etwas gemacht hat und gibt ihm in diesem fall den Befehl eine Bombe zu legen ("BombeExplodes" wird für die entsprechende bombe bei "Game" registiert")
SpielerX legt die Bombe und startet den Timer zur Explosion.
Bombe explodiert und imformiert alle dies wissen wollen darüber.
"Game" bemerkt, dass eine Bombe explodiert ist entfernt diese vom feld und legt entsprechend der sprengkraft Feuer in die felder (hier wird nun "FeuerErlischt" registriert und der Timer für die dauer des brennens gestartet)
Ist das Feuer 'erloschen', wird es vom feld entfernt un ein invalidate an das "GamePanel" geschickt.
Folgend kommt noch code, aber hier erstmal mein Problem an dem Beispiel:
Sobald das Feuer "erloschen" und entfernt wird, stürzt das "GamePanel" (Also die Zeichenoberfläche) MANCHMAL ab, da der fehler sporadisch auftritt, dacht ich an einen Threadübertritt..., aber gezielte lock-befehle haben bisher nix gebracht.
Zusätzlich, stürzt die Zeichenoberfläche auch MANCHMAL ab, wenn 2 bomben nebeneinander explodieren (undzwar ZUR Explosion und nich erst beim erlischen des Feuers)
das field "feldListe" sieht wie folgt aus:
private Dictionary<Point, List<FieldObject>> felderListe;
Ein "FieldObject" kann ein Spieler, eine Bombe, Feuer oder ein aufhebbaren Item sein.
Bombe-Klasse:
Im Konstruktor der Bombenklasse wird "BombeZünden()" ausgelöst.
private void BombeZünden() {
Thread t = new Thread(new ParameterizedThreadStart(SprengTimer));
t.IsBackground = false;
t.Start(sprengkraft);
}
private void SprengTimer(object sprengkraft_) {
Thread.Sleep(3500);
Sprengen((int)sprengkraft_);
}
private void Sprengen(int sprengkraft_) {
OnExploding(this);
}
Game-Klasse:
private void BombExplodes(object sender, Bombe.BombeEventArgs e) {
lock(felderListe) {
felderListe[e.Bombe.Point].Remove(e.Bombe);
CreateFeuerAt(e.Bombe.Point);
#region North
for(int i = 1; i <= e.Bombe.Sprengkraft; i++) {
Point p = new Point(e.Bombe.Point.X, e.Bombe.Point.Y - i);
if(p.Y >= 0)
if(CreateFeuerAt(p)) break;
}
#endregion
#region South
...
#endregion
#region East
...
#endregion
#region West
...
#endregion
e.Bombe.Gamer.GiveItem(Gamer.Items.Bombe);
}
}
private bool CreateFeuerAt(Point p) {
bool ret = false;
Feuer f = new Feuer(p);
f.FeuerErlischt += new Feuer.FeuerEventHandler(FeuerErlischt);
FelderListe[p].Add(f);
if(Game.getObjectFromList<Stein>(FelderListe[p], true) != null)
ret = true;
OnUpdateGamePanel(p.X, p.Y, fieldSize, fieldSize);
return ret;
}
private void FeuerErlischt(object sender, Feuer.FeuerEventArgs e) {
lock(felderListe) {
int index = Game.GetSpecificObjectIndexFromList<Feuer>(felderListe[e.Feuer.Point], e.Feuer);
if(index >= 0) {
felderListe[e.Feuer.Point].RemoveAt(index);
OnUpdateGamePanel(e.Feuer.Point.X, e.Feuer.Point.Y, fieldSize, fieldSize);
}
}
}
Feuer-Klasse:
Auch hier wird "FeuerAnzünden()" im Konstruktor ausgelöst.
private void FeuerAnzünden() {
Thread t = new Thread(new ThreadStart(BrennTimer));
t.IsBackground = false;
t.Start();
}
private void BrennTimer() {
Thread.Sleep(750);
Löschen();
}
private void Löschen() {
OnLöschen(this);
}
Ich hoffe ihr könnt mir einen Hinweis geben, wie ich dieses Problem lösen kann, Anregungen zur Fehlersuche (Vorgehensweise) wären auch super, mir gehen nämlich langsam die Ideen aus.
PS: Eine kleine zwischen Frage hät ich noch, ist es klug und OK, wenn man auf ein Panel zeichner, oder wäre da eine PictureBox besser geeignet, gibts da Vor-/Nachteile?
mfg
Ani
danke @cat, so wollt ichs eigentlich
mfg
ani
aber "Human" und "NPC" erben doch von "Gamer"
sollte es da nicht möglich sein einen Gamer in ein "Human" oder "NPC" umzuwandeln?
object o = "Test";
string s = (string)o;
Hallo leute,
ich hab folgenden Sachverhalt:
Gamer
<---Human
<---NPC
also die Klassen "Human" und "NPC" erben von der Klasse "Gamer".
Beim erstellen eines Spiels gibt es ein Dictonary<int, Gamer> gamerList.
Dieses Dictonary soll je nach Auswahl mit "Human"-Spielern und "NPC"-Spieler gefüllt werden:
Gamer g = new Gamer(..., ..., ...);
if(bNPC) gamerList.Add(g.ID, (NPC)g);
else gamerList.Add(g.ID, (Human)g);
,aber der cast funktioniert iwie nicht, der Compiler sagt mir:
Das Objekt des Typs "Gamer" kann nicht in Typ "Human" umgewandelt werden.
mfg
ani
Hallo leute,
ich hab mir nach dem vorbild in folgendem link ein customWindow gebastelt und bisher funktioniert auch alles super.
[Artikel] Custom Window Border für Form's
Doch als ich nun zwecks eines Dialogs die "BaseForm" vererben wollte und mittels "ShowDialog()" anzeigen wollte, erscheint das fenster zwar in all seiner pracht, lässt sich aber weder vergrößern (über die ränder) noch maxi-/minimieren oder per close-button schließen.
habt ihr vll eine pauschale lösung, oder soll ich den gesamten code der baseForm mal posten?
mfg
ani
klingt intgeressant, hast da evtl nen link zu, oder würdest mir das erklären?
edit: achso lol, is ja nur ne eigentschaft.
hmm, naja aber wenn ich das so mache, is der transperente teil immer noch "berührbar" (also wenn ich mit der maus drüber gehe) und genau das soll nich sein
Hallo leute,
wie man einer Form ein bestimmtest aussehen zuweist (z.b. ein kreis oder dreieck...) weis ich und hab auch schon mit graphicpaths rumgespielt.
Ich würd nun gern folgendes machen:
Ich hab ein png-bild, mit einer recht simplen figur, ist es irgendwie (auf einfachem wege) möglich einen equivalenten graphicpath dazu zu erstellen, damit ich diesen als Form-Region nehmen kann?
mfg
ani