Beides sind aber die einzigen zwei Möglichkeiten, denn der Compiler muß ja die Abhängigkeiten irgendwie auflösen
Danke, auch wenn es nicht die Antwort war, die ich mir erhofft habe 😁
Sooo viel steht da nicht drin, dass ich ein neues Projekt dafür aufmachen will (denn davon habe ich eigentlich schon zu viele).
Kann ich die Klasse "ScriptBase" nicht zur Laufzeit nochmal kompilieren und dann den refferencedAssemblies hinzufügen?
private CompilerResults GenerateScriptingClass(String sourceCode)
{
string source =
@"
using System;
using MeineExternenKlassen;
using ScriptBase;
namespace Scripting
{
public class Scripting: ScriptBase
{
public Scripting()
{
Console.WriteLine(""create scripting "" +"" ""+this);
}
"
+ sourceCode + @"
}
}";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v4.0"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false
};
Hier die ScriptBase erzeugen? Am Besten im Speicher und nicht als Datei.
Und dann mit einbinden.....
compilerParams.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
compilerParams.ReferencedAssemblies.Add("MeineExternenKlassen.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
{
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.Line + " " + error.ErrorNumber + " " + error.ErrorText));
throw new Exception("Mission failed!");
}
return results;
}
Ein nachträgliches Verändern einer bestehenden Klasse und Assembly macht keinen Sinn und funktioniert auch nicht. Das partial-Schlüsselwort ist eine Neueinführung von Microsoft in C# (eventuell auch VB.NET) um hauptsächlich Designer-Code von User-Code zu trennen.
Um Properties und Funktionen zu einer bestehenden Klasse hinzuzufügen kannst du gerne die Vererbung verwenden, ist prima dazu geeignet und bestens in C# integriert 😉
Genau vor diesem Problem stehe ich gerade. Wie kann ich von Klassen aus meinem Hauptprogramm erben?
Der Hintergrund ist folgender:
private CompilerResults GenerateScriptingClass(String sourceCode)
{
string source =
@"
using System;
using MeineExternenKlassen;
using ScriptBase;
namespace Scripting
{
public class Scripting: ScriptBase
{
public Scripting()
{
Console.WriteLine(""create scripting "" +"" ""+this);
}
"
+ sourceCode + @"
}
}";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v4.0"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false
};
compilerParams.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
compilerParams.ReferencedAssemblies.Add("MeineExternenKlassen.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
{
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.Line + " " + error.ErrorNumber + " " + error.ErrorText));
throw new Exception("Mission failed!");
}
return results;
}
Wenn ich die Vererbung von ScriptBase entferne klappt es:
Was mir fehlt:
Beispeil für Benutzereingabe im ScriptEditor:
int main(){
schalteFunktion("parameter4", 11123.11);
boolean b1 = prüfeSensor("seite1");
boolean b2 = prüfeSensor("seite2");
if((b1||b2) == false){
MeineExternenKlassen.getInstance().log("fehler xyz "+b1 +" " +b2)
return 1;
}
return 0;
}
Über ScriptBase würde ich neben "schalteFunktion" und "prüfeSensor" zum Beispiel noch eine Funktion "log(String s)" anbieten, die dann das "MeineExternenKlassen.getInstance().log(....)" ersetzt, um die Lesbarkeit zu verbessern.
(unsaubere) Lösungswege:
-Ich könnte natürlich den Quellcode aus der "ScriptBase" auch über copy-paste mit in den sourceCode von Script packen..... 🤔
-Oder ich könnte aus ScriptBase eine DLL erzeugen und diese dann den compilerParams hinzufügen
Beides ist irgentwie unschön.
Hat jemand einen Vorschlag, wie ich die Sache schöner gelöst bekomme?
Vielen Dank 👍
Vielen Dank, da hatte ich mal wieder Tomaten auf den Augen 8)
Ich dachte ich würde damit den Standart-Setter überschreiben und habe nicht gemerkt, dass ich ein loop gebaut habe
Mir der "T-Virus-Anpassung" klappt es! 👍
Die Klasse wird zu erst durch einen XML-Parser gefüllt und anschließend manuell weiterverarbeitet.
Beispiel:
public class GUI
{
// public String LANGUAGE;
public string LANGUAGE
{
get { return LANGUAGE; }
set { Console.WriteLine("changed language " + value); LANGUAGE = value; return; }
}
}
Leider hängt er sich beim Füllen auf. Output:
changed language ger
changed language ger
changed language ger
changed language ger
changed language ger
changed language ger
changed language ger
changed language ger
changed language ger
....
Was mache ich falsch? 🤔
Unter WinForms hatte ich die Paint-Methode überschrieben
private void dataGrid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 2)
{
if (e.Value != null)
{
// abbruch wenn Tabellenüberschrift
if (e.RowIndex < 0)
return;
if (dataGrid.Rows[e.RowIndex].Cells[2].Value != null)
dataGrid.Rows[e.RowIndex].Cells[2].Style.BackColor = ColorTranslator.FromHtml(dataGrid.Rows[e.RowIndex].Cells[2].Value.ToString());
}
}
}
Das lässt sich doch jetzt sicher eleganter über den XAML-Code umsetzen oder?
Vielen Dank! Das kam mir garnicht in den Sinn 8)
Nach der Anpassung in der Klasse D3D läuft der Code jetzt
vorher
Nullpointer-Exception
_backBuffer.Dispose();
_backBuffer = new Texture(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
_device.SetRenderTarget(0, _backBuffer.GetSurfaceLevel(0));
nachher
if (_backBuffer != null)
_backBuffer.Dispose();
_backBuffer = new Texture(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
_device.SetRenderTarget(0, _backBuffer.GetSurfaceLevel(0));
Die Version wird nicht mehr zum Download angeboten
http://sharpdx.org/download/
Dieses Beispiel hier macht im Prinzip auch genau das was ich brauche, lässt sich aber auch nicht kompilieren.
DirectX in WPF integrieren
Fehlermeldung:
Fehler 1 Der Typ 'SharpDX.ComObject' ist in einer nicht referenzierten Assembly definiert. Fügen Sie einen Verweis auf die Assembly 'SharpDX, Version=2.5.0.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a' hinzu.
SharpDX kommt über nuget in Version 2.6.3.
Moin,
das sample kannte ich schon. Ist viel zu kompliziert für das was ich vorhabe und lässt sich auch nicht kompilieren 😦
Ich möchte eine Anwendung von WinForms nach WPF portieren und stolpere an einer Stelle.
Ich habe eine Klasse, die von Panel erbt und mit SlimDX zeichnet. Aus dieser Klasse möchte ich ein UserControl machen.
Das Device wird im Panel so erzeugt
PresentParameters presentParams = new PresentParameters();
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.Windowed = true;
Device device3D = new Device(new Direct3D(), 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, presentParams);
Im UserControl gibt es aber kein this.Handle und die Beispiele die ich bisher im Netz gefunden habe, sind zu kompliziert, für das was ich damit bewirken möchte.
Es gibt Appender die die Logdaten zu einer anderen Kiste verschicken. Vllt ist es ja was für dich.
Ich habe beim Anwender meistens keine andere Kiste und das Programm darf nicht nach Hause telefonieren
Genauso machen wie bei der Konfiguration?
Damit merke ich, dass die Datei angefasst wurde, aber nicht wo.
Ich könnte mir das Format so vorstellen:
<Datum> <Logging-Nachricht> <Prüfsumme aus: Datum&Nachricht&Prüfsumme der letzten Zeile>
Damit kann man auch genau sehen, welche Einträge fehlen 😁
Es muss weiterhin lesbar sein.
Es ist nicht immer die Putzfrau, manchmal gehen auch so mal "ein paar Bytes verloren". 😁
Ich hab keine Lust auf Diskussionen und Schuldzuweisungen. Wenn "Bytes verloren gehen", dann gibs nen Alarm und es wird die Hardware (oder der Bediener) ausgetauscht 8)
Wer kennt es nicht? Die Software läuft auf einmal nicht mehr und man sucht sich nen Wolf. Es wurde nichts geändert, aber es läuft einfach nicht mehr. "Die Software hat bugs!", "Das Programm ist abgekackt!",..... Nach Ewigkeiten kommt dann heraus, dass "die Putzfrau" an Parametern oder der Hardware manipuliert hat 😉
Um diesen Diskussionen aus dem Weg zu gehen, wird die Konfigarationsdatei signiert und kann deswegen nicht mehr so einfach über einen Editor verändert werden. Jede Parameter-Änderung und jedes kritische Hardware-Event wird gelogt.
Um die Sache rund zu machen, wünsche ich mir noch eine Signierung der Logeinträge, damit "böse" Einträge nicht einfach verschwinden können.
Ich bin bestimmt nicht der erste mit solcher Paranoia, konnte aber bisher keine passende Lösung finden.
😁
Nur so, bei ner HD4000 gibst nur ne Exception und der Graka Treiber unter W8.1 reinitialisiert sich mit deiner Beispielanwendung.
Vielen Dank für Dein Feedback.
Ich entwickel mit **Windows 7 **und dem "DXSDK_Jun10.exe". Auf einem anderen Win7-Rechner mit einer Radeon HD6450 Karte läuft es auch fehlerfrei.
Was für eine Exception fliegt denn genau?
Bei einem Drahtgittermodell ohne Beleuchtung dürfte sich jede normale Grafikkarte eher langweilen.
Vielen Dank 👍
Ich habe jetzt meine Lösung mit der ich erstmal zufrieden bin. Durch das Anpassen der App.config läuft nun auch Microsoft.DirectX mit .Net 4.5.1
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsDirect
{
public partial class DirectPanel : Panel
{
private Device m_oDevice = null;
private PresentParameters m_oPresentParams = null;
VertexBuffer oVertexBuffer;
Boolean scrolling = false;
int mouseX = 0;
int mouseY = 0;
int diffX = 0;
int difY = 0;
int zoomLevel = -100;
int count = 2000000;
public directPanel()
{
InitializeComponent();
//Device-Beschreibung
m_oPresentParams = new PresentParameters();
m_oPresentParams.SwapEffect = SwapEffect.Discard;
m_oPresentParams.Windowed = true;
// Hier wird auf den HANDLE gezeigt "this"
m_oDevice = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, m_oPresentParams);
m_oDevice.RenderState.ShadeMode = ShadeMode.Gouraud;
//Vertex-Buffer erstellen
oVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), count, m_oDevice, Usage.None,
CustomVertex.PositionColored.Format, Pool.Managed);
CustomVertex.PositionColored[] vecListe = new CustomVertex.PositionColored[count];
for (int i = 0; i < (count - 1); i += 2)
{
vecListe[i].X = 0; vecListe[i].Y = 0; vecListe[i].Z = 1; vecListe[i].Color = Color.Orange.ToArgb();
vecListe[i + 1].X = i % 1000; vecListe[i + 1].Y = (i + 30) % 940; vecListe[i + 1].Z = 1; vecListe[i + 1].Color = Color.Orange.ToArgb();
}
oVertexBuffer.SetData(vecListe, 0, LockFlags.None);
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.direct_MouseWheel);
}
public void Render()
{
if (m_oDevice == null)
return;
m_oDevice.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
m_oDevice.BeginScene();
m_oDevice.RenderState.CullMode = Cull.None;
m_oDevice.RenderState.Lighting = false;
m_oDevice.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)(m_oPresentParams.BackBufferWidth / m_oPresentParams.BackBufferHeight), 1.0f, 500.0f);
m_oDevice.Transform.View = Matrix.LookAtLH(new Vector3(diffX, difY, zoomLevel), new Vector3(diffX, difY, 0), new Vector3(0, 1, 0));
m_oDevice.VertexFormat = CustomVertex.PositionColored.Format;
m_oDevice.SetStreamSource(0, oVertexBuffer, 0);
m_oDevice.DrawPrimitives(PrimitiveType.LineList, 0, count / 2);
m_oDevice.EndScene();
m_oDevice.Present();
}
private void InitializeComponent()
{
this.SuspendLayout();
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.directPanel_MouseDown);
this.MouseEnter += new System.EventHandler(this.directPanel_MouseEnter);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.directPanel_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.directPanel_MouseUp);
this.ResumeLayout(false);
}
private void directPanel_MouseDown(object sender, MouseEventArgs e)
{
mouseX = e.X;
mouseY = e.Y;
scrolling = true;
}
private void directPanel_MouseUp(object sender, MouseEventArgs e)
{
scrolling = false;
}
private void directPanel_MouseMove(object sender, MouseEventArgs e)
{
if (scrolling)
{
diffX -= (e.X - mouseX);
difY += (e.Y - mouseY);
Console.WriteLine("Moved : " + diffX + " " + difY);
mouseX = e.X;
mouseY = e.Y;
Render();
}
}
private void directPanel_MouseEnter(object sender, EventArgs e)
{
this.Focus();
}
private void direct_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Delta < 0)
zoomLevel += 10;
else
zoomLevel -= 10;
Render();
}
}
}
Auf welchen Grafikkarten hast du dein Programm getestet?
-integrierte Intel HD
-NVidia Quattro K1100M
fällt mir kein Anwendungs-Beispiel ein, wo man die Anforderung hätte, 1 Mio Linien gleichzeitig auf dem Monitor darzustellen.
Zum Beispiel CAD-Programme, wenn Du Drahtgittermodelle darstellen willst.
Lade doch mal irgendwo eine kompilierbare Solution hoch (auch mit SharpDX, wenn kein NuGet), dann kann ich ja mal schauen, wie schnell es bei mir läuft und vll. finde ich ja auch ein Fehler.
Vielen Dank 👍WindowsFormsSlim.zip
Ich bin Stück für Stück Anleitungen und Bücher zum Thema durchgegangen, aber das Ergebnis ist leider immernoch zu langsam.
Die Darstellung von 1 Mio Linien sollten eine Kleinigkeit für eine Grafikkarte sein.
Der Aufruf des Konstruktors dauert ca 300ms. Der Erste Click auf "fill" dauert laut Stop-Uhr 120ms, jeder weitere 0ms. Bis die Linien jedoch auf dem Monitor erscheinen vergeht geht eine Sekunde.
Wo liegt mein Fehler, was mache ich falsch?
Windows Form-Anwendung
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void fill_Click(object sender, EventArgs e)
{
linePanel_21.Render(true);
}
private void clear_Click(object sender, EventArgs e)
{
linePanel_21.Render(false);
}
}
}
Panel
using SlimDX;
using SlimDX.Direct3D9;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
class LinePanel_2 : Panel
{
VertexBuffer vertexBuffer;
private Device device = null;
private PresentParameters presentParams = null;
VertexDeclaration vertexDecl;
int count = 2000000;
public LinePanel_2()
{
//Device-Beschreibung
presentParams = new PresentParameters();
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.Windowed = true;
Direct3D d3d = new Direct3D();
device = new Device(d3d, 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, presentParams);
ColoredVertex[] vecListe = new ColoredVertex[count];
for (int i = 0; i < (count - 1); i += 2)
{
vecListe[i] = new ColoredVertex(new Vector3(0, 0, 1), Color.Red.ToArgb());
vecListe[i + 1] = new ColoredVertex(new Vector3(i % 1000, (i + 30) % 1000, 1), Color.Red.ToArgb());
}
vertexBuffer = new VertexBuffer(device, count * Marshal.SizeOf(typeof(ColoredVertex)), Usage.WriteOnly, VertexFormat.None, Pool.Managed);
var stream = vertexBuffer.Lock(0, 0, LockFlags.None);
stream.WriteRange(vecListe);
vertexBuffer.Unlock();
device.SetRenderState(RenderState.Lighting, false);
vertexDecl = new VertexDeclaration(device, new[] {
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
VertexElement.VertexDeclarationEnd });
}
public void Render(Boolean fillMode)
{
Stopwatch sw = new Stopwatch();
sw.Restart();
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, new Color4(0.3f, 0.3f, 0.3f), 1.0f, 0);
if (fillMode)
{
device.BeginScene();
device.SetStreamSource(0, vertexBuffer, 0, Marshal.SizeOf(typeof(ColoredVertex)));
device.VertexDeclaration = vertexDecl;
device.DrawPrimitives(PrimitiveType.LineList, 0, count / 2);
device.EndScene();
}
// +++++++++++++++++++++++++
// Funktion dauert lange
device.Present();
//++++++++++++++++++++++++++
sw.Stop();
Console.WriteLine(count / 2 + " lines in " + sw.ElapsedMilliseconds);
}
[StructLayout(LayoutKind.Sequential)]
struct ColoredVertex
{
public Vector3 Position;
public int Color;
public ColoredVertex(Vector3 v, int c)
{
Position = v;
Color = c;
}
public static readonly VertexFormat Format = VertexFormat.Position | VertexFormat.Diffuse;
}
}
}
Du musst die Draw Methode blockieren, sonst bringts natürlich nichts.
Danke! Nun heizt die GPU nicht mehr.
Parallel versuche ich noch das SlimDX Beispiel schneller zu bekommen, weil es einfacher ist und von der Logik her besser zu dem passt, was ich mir vorstelle. Ich benötige kein 3D.
Der Verzicht auf die Erzeugung der zwei Point-Objekte beim Aufruf der DrawLine-Methode brachte leider kaum Gewinn (~1800ms auf ~1750ms).
for (int loopX = 0; loopX < obje; loopX++)
m_renderTarget.DrawLine(bru, 0, 0, 1000, loopX % 10000);
Ich habe bisher leider nicht herausgefunden, wie ich einen Array übergeben kann, um alles mit einem einzigen Methodenaufruf zu verarbeiten.
Hier mein anderes Sample: Windows-Forms-Element mit SlimDx/Direct2D.
Vorteil: Scrollen und Zoomen einfach über die Transform-Matrix. Kein GPU-Load nachdem die Linien gezeichnet wurden.
Nachteil: Langsamer als das 3D-Beispiel (1mio Linien dauern über 2 Sekunden)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//Some namespace mappings
using D2D = SlimDX.Direct2D;
using System.Drawing.Drawing2D;
using SlimDX;
using SlimDX.Direct2D;
using System.Diagnostics;
using SlimDX.Direct3D11;
namespace WindowsFormsMitD2D
{
public partial class UserControl1 : UserControl
{
//Resources for Direct2D rendering
private D2D.Factory m_factory;
private D2D.WindowRenderTarget m_renderTarget;
private D2D.LinearGradientBrush m_backBrushEx;
private D2D.GradientStopCollection m_backBrushGradient;
//Some generic members
private System.Drawing.Brush m_backBrushGdi;
private bool m_initialized;
public UserControl1()
{
InitializeComponent();
//Update control styles
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
//Update back brush
m_backBrushGdi = new SolidBrush(this.BackColor);
}
private void InitializeGraphics()
{
Console.WriteLine("3");
//Create factory object
m_factory = new D2D.Factory(D2D.FactoryType.SingleThreaded, D2D.DebugLevel.None);
//Create the render target
m_renderTarget = new D2D.WindowRenderTarget(m_factory, new D2D.WindowRenderTargetProperties()
{
Handle = this.Handle,
PixelSize = this.Size,
PresentOptions = D2D.PresentOptions.Immediately
});
//Create linear gradient brush
D2D.GradientStop[] gradientStops = new D2D.GradientStop[]
{
new D2D.GradientStop(){ Position = 0f, Color = new Color4(Color.LightGray) },
new D2D.GradientStop(){ Position = 1f, Color = new Color4(Color.LightSteelBlue) }
};
m_backBrushGradient = new D2D.GradientStopCollection(m_renderTarget, gradientStops);
m_backBrushEx = new D2D.LinearGradientBrush(
m_renderTarget,
m_backBrushGradient,
new D2D.LinearGradientBrushProperties()
{
StartPoint = new PointF(0, this.Height),
EndPoint = new PointF(0, 0)
});
//Update initialization flag
m_initialized = true;
}
/// <summary>
/// Unloads all graphics resources.
/// </summary>
private void UnloadGraphics()
{
if (m_backBrushEx != null) { m_backBrushEx.Dispose(); }
if (m_backBrushGradient != null) { m_backBrushGradient.Dispose(); }
if (m_renderTarget != null) { m_renderTarget.Dispose(); }
if (m_factory != null) { m_factory.Dispose(); }
m_backBrushEx = null;
m_backBrushGradient = null;
m_renderTarget = null;
m_factory = null;
}
/// <summary>
/// Called when window opens.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if ((!m_initialized) || (!this.DesignMode))
{
InitializeGraphics();
}
}
/// <summary>
/// Called when window closes.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
if (m_initialized)
{
UnloadGraphics();
}
}
protected override void OnResize(EventArgs e)
{
Console.WriteLine("RESIZE! ");
base.OnResize(e);
if ((this.Width > 0) && (this.Height > 0))
{
if (m_backBrushGdi != null) { m_backBrushGdi.Dispose(); }
m_backBrushGdi = new System.Drawing.Drawing2D.LinearGradientBrush(
new Point(0, this.Height),
new Point(0, 0),
Color.LightGray,
Color.LightSteelBlue);
if (m_initialized)
{
//Resize render target
m_renderTarget.Resize(this.Size);
m_backBrushEx.StartPoint = new PointF(0, this.Height);
}
}
}
/// <summary>
/// Called when control has to paint itself.
/// </summary>
/// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (m_initialized)
{
m_renderTarget.AntialiasMode = AntialiasMode.PerPrimitive;
m_renderTarget.BeginDraw();
try
{
m_renderTarget.Clear(new Color4(this.BackColor));
//Perform all Direct2D rendering here
m_renderTarget.FillRectangle(
m_backBrushEx,
new Rectangle(new Point(), this.Size));
//Apply quality
// D2D.InterpolationMode interpolationMode = D2D.InterpolationMode.NearestNeighbor;
// interpolationMode = D2D.InterpolationMode.Linear;
Pen p = new Pen(Brushes.Black);
// for (int loopX = 0; loopX < 10000; loopX++)
// e.Graphics.DrawLine(p, new Point(0, 0), new Point(300, loopX));
List<Point> liste = new List<Point>();
SolidColorBrush bru = new SolidColorBrush(m_renderTarget, new Color4(Color.Black));
Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();
int obje = 1000000;
for (int loopX = 0; loopX < obje; loopX++)
{
m_renderTarget.DrawLine(bru, new Point(0, 0), new Point(1000, loopX % 10000));
}
sw.Stop();
Console.WriteLine(obje + " objects in " + sw.ElapsedMilliseconds);
Console.WriteLine("Matrix " + m_renderTarget.Transform.M11 + " " + m_renderTarget.Transform.M12 + " " + m_renderTarget.Transform.M21 + " " + m_renderTarget.Transform.M22 + " " + m_renderTarget.Transform.M31 + " " + m_renderTarget.Transform.M32);
}
finally
{
m_renderTarget.EndDraw();
}
}
}
public void scaleUp()
{
Matrix3x2 transMatrix = m_renderTarget.Transform;
transMatrix.M11++;
transMatrix.M22++;
transMatrix.M31 -= (m_renderTarget.Size.Width / 2);
transMatrix.M32 -= (m_renderTarget.Size.Height / 2);
m_renderTarget.Transform = transMatrix;
// Invalidate();
}
public void scaleDown()
{
Matrix3x2 transMatrix = m_renderTarget.Transform;
transMatrix.M31 -= 100;
m_renderTarget.Transform = transMatrix;
// Invalidate();
}
}
}
Kann man das vielfache Aufrufen der Funktion
m_renderTarget.DrawLine(bru, new Point(0, 0), new Point(1000, loopX % 10000));
vermeiden, indem man einen kompletten Array an Linien / Punkten übergibt wie im Beispiel zuvor?
Aleine durch das Blockieren der Update-Funktion wird das Performance-Problem nicht gelöst. Die GPU brennt trotzdem
protected override void Update(GameTime gameTime)
{
// Rotate the cube.
var time = (float)gameTime.TotalGameTime.TotalSeconds;
//basicEffect.World = Matrix.RotationY(time);
// basicEffect.Projection = Matrix.PerspectiveFovRH((float)Math.PI / 0.40f, (float)GraphicsDevice.BackBuffer.Width / GraphicsDevice.BackBuffer.Height, 0.1f, 100.0f);
// basicEffect.View = Matrix.LookAtRH(new Vector3(0, 0, zoom), new Vector3(lookX, 0, 0), Vector3.UnitY);
// basicEffect.Projection = Matrix.OrthoRH(zoom, zoom, 0, 1001.0f);
if (updateGrafics)
{
Console.WriteLine("UPDATE");
base.Update(gameTime);
updateGrafics = false;
}
}
protected override void Draw(GameTime gameTime)
{
// Clears the screen with the Color.CornflowerBlue
GraphicsDevice.Clear(Color.CornflowerBlue);
// Setup the vertices
GraphicsDevice.SetVertexBuffer(vertices);
GraphicsDevice.SetVertexInputLayout(inputLayout);
// Apply the basic effect technique and draw the rotating cube
basicEffect.CurrentTechnique.Passes[0].Apply();
// GraphicsDevice.Draw(PrimitiveType.TriangleList, vertices.ElementCount);
GraphicsDevice.Draw(PrimitiveType.LineList, vertices.ElementCount);
// Handle base.Draw
base.Draw(gameTime);
}
public void zoomIn()
{
updateGrafics = true;
}
public void zoomOut()
{
updateGrafics = true;
}
Ich glaube mit SharpDX solltest du dann weit kommen. Linien haben in DirectX glaube ich immer eine Breite von einem Pixel, unabhängig von ihrem Abstand zur Kamera etc.
Nehme jetzt Linien mit 1px Breite, um es einfacher zu halten.
Ich habe mit dem Beispiel "SwitchContext.WPF" von den SharpDX Samples etwas rumprobiert.
Geschwindigkeit ist top! 40mio Linien in unter 2 Sekunden.
Von der Sache her genau das was ich brauche. Ich kippe die ganzen Koordinaten einmal in den VertexBuffer und den Rest macht die Karte. Arbeitsspeicherverbrauch ist nun auch völlig im Rahmen.
MiniCube.cs
public class MiniCubeGame : Game
{
private GraphicsDeviceManager graphicsDeviceManager;
private BasicEffect basicEffect;
private Buffer<VertexPositionColor> vertices;
private VertexInputLayout inputLayout;
/// <summary>
/// Initializes a new instance of the <see cref="MiniCubeGame" /> class.
/// </summary>
public MiniCubeGame()
{
// Creates a graphics manager. This is mandatory.
graphicsDeviceManager = new GraphicsDeviceManager(this);
// Setup the relative directory to the executable directory
// for loading contents with the ContentManager
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
// Creates a basic effect
basicEffect = ToDisposeContent(new BasicEffect(GraphicsDevice)
{
VertexColorEnabled = true,
View = Matrix.LookAtRH(new Vector3(0, 0, 100), new Vector3(000, 0, 0), Vector3.UnitY),
Projection = Matrix.OrthoRH(1000, 1000, 0, 1001.0f),
World = Matrix.Identity
});
int countVert = 80000000;
Stopwatch sw = new Stopwatch();
sw.Restart();
VertexPositionColor[] liste = new VertexPositionColor[countVert];
for (int i = 0; i < (countVert - 1); i++)
{
liste[i++] = new VertexPositionColor(new Vector3(0, 0, 1.0f), Color.Orange);
liste[i++] = new VertexPositionColor(new Vector3(1000, (i % 10000) * 0.1f, 1.0f), Color.Orange);
}
sw.Stop();
Console.WriteLine(countVert / 2 + " lines in " + sw.ElapsedMilliseconds);
// Creates vertices for the cube
vertices = ToDisposeContent(Buffer.Vertex.New(GraphicsDevice, liste));
ToDisposeContent(vertices);
// Create an input layout from the vertices
inputLayout = VertexInputLayout.FromBuffer(0, vertices);
base.LoadContent();
}
protected override void Initialize()
{
Window.Title = "MiniCube demo";
base.Initialize();
}
protected override void Update(GameTime gameTime)
{
// Rotate the cube.
var time = (float)gameTime.TotalGameTime.TotalSeconds;
//basicEffect.World = Matrix.RotationY(time);
// basicEffect.Projection = Matrix.PerspectiveFovRH((float)Math.PI / 0.40f, (float)GraphicsDevice.BackBuffer.Width / GraphicsDevice.BackBuffer.Height, 0.1f, 100.0f);
// basicEffect.View = Matrix.LookAtRH(new Vector3(0, 0, zoom), new Vector3(lookX, 0, 0), Vector3.UnitY);
// basicEffect.Projection = Matrix.OrthoRH(zoom, zoom, 0, 1001.0f);
Console.WriteLine("UPDATE");
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
// Clears the screen with the Color.CornflowerBlue
GraphicsDevice.Clear(Color.CornflowerBlue);
// Setup the vertices
GraphicsDevice.SetVertexBuffer(vertices);
GraphicsDevice.SetVertexInputLayout(inputLayout);
// Apply the basic effect technique and draw the rotating cube
basicEffect.CurrentTechnique.Passes[0].Apply();
// GraphicsDevice.Draw(PrimitiveType.TriangleList, vertices.ElementCount);
GraphicsDevice.Draw(PrimitiveType.LineList, vertices.ElementCount);
// Handle base.Draw
base.Draw(gameTime);
}
public void zoomIn()
{
}
public void zoomOut()
{
}
}
MainWindow.xml.cs
namespace MiniCube.SwitchContext.WPF
{
using System;
using System.Windows;
using System.Windows.Controls;
using SharpDX.Toolkit;
public partial class MainWindow
{
private readonly Game _game;
public MainWindow()
{
InitializeComponent();
_game = new MiniCubeGame();
RunGameOn(button1, button2, contentContainer1);
}
private void Button1Click(object sender, RoutedEventArgs e)
{
RunGameOn(button1, button2, contentContainer1);
}
private void Button2Click(object sender, RoutedEventArgs e)
{
RunGameOn(button2, button1, contentContainer2);
}
private void RunGameOn(UIElement disableButton, UIElement enableButton, ContentControl contentContainer)
{
DisposeContent(contentContainer1);
DisposeContent(contentContainer2);
disableButton.IsEnabled = false;
enableButton.IsEnabled = true;
var element = new SharpDXElement
{
SendResizeToGame = true,
SendResizeDelay = TimeSpan.FromSeconds(2),
LowPriorityRendering = false,
};
contentContainer.Content = element;
if (_game.IsRunning)
_game.Switch(element);
else
_game.Run(element);
}
private void DisposeContent(ContentControl contentContainer)
{
var element = contentContainer.Content as SharpDXElement;
contentContainer.Content = null;
if (element != null)
element.Dispose();
}
private void contentContainer1_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (e.Delta > 0)
((MiniCubeGame)_game).zoomIn();
else
((MiniCubeGame)_game).zoomOut();
}
}
}
Was mir noch fehlt um es für mich nutzbar zu machen ist:
Um was geht es eigentlich? Am Anfang hast du von DirectX geredet, jetzt sprichst du von einer WinForms-Anwendung, die ein WPF-Control hostet...?
Gegeben ist eine Windows Forms Anwendung, die ein neues Feature benötigt und zwar die Darstellung einer Karte. Die Karte benötigt die Funktionen Scrollen und Zoomen, weil sie sehr groß und detailiert ist.
Die Definition der Abbildung liegt vor als Double[]={startLinieX1, startLinieY1, endLinieX1, endLinieY1, startLinieX2, startLinieY2, endLinieX2, endLinieY2,.......................}
Deswegen habe ich ein WPF-Control eingefügt. Und WPF nutzt ja die Hardwarebeschleunigung mit DirectX. Die Anzahl der Striche lässt sich nicht reduzieren, weil sie gegeben ist. Es wird jedes Detail benötigt.
Weil das mit dem WPF-Control Element zu langsam war habe ich mit SlimDX und SharpFX angefangen.
Natürlich wird man bei 1 Mio weißen Linien nur einen fetten weißen Fleck am Monitor sehen, wenn diese alle gleichmäßig auf die sichtbare Fläche verteilt sind
Das ist korrekt. Wenn man ganz weit heraus-zommt, sodass man die komplette Karte sehen kann, dann sieht man teilweise gefüllte Flächen. Das ist so beabsichtigt. Ich erhöhe dazu bei jedem Schritt des Herauszoomens extra die Strichstärke, weil die feinen Linien sonst ab einem gewissen Faktor garnicht mehr angezeigt werden und vom Bild verschwinden.
Wird das Bild vergrößtert, so werden die Striche wieder dünner gezeichnet, sodass man die Details erkennen kann.
Analyse aus VS2013
Habe es endlich geschafft die "Wpf Performance Suite" ans Laufen zu bekommen.
Dazu war es nötig:
Leider hat mich das nicht wirklich schlauer gemacht.
Eingebunden ist die Grafikkomponente via Element-Host in ein Windows Form.
Der Teil für die Darstellung in der WPF-Komponente:
<ScrollViewer x:Name="scrollViewer" DockPanel.Dock="Left" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Center" Focusable="False" PreviewMouseWheel="scrollViewer_PreviewMouseWheel">
<Canvas x:Name="canvas" Background="#FFA4A3A3" HorizontalAlignment="Center" VerticalAlignment="Center" ScrollViewer.VerticalScrollBarVisibility="Disabled" MinWidth="1000" MinHeight="1000"/>
</ScrollViewer>
Ich habe prinzipiell das gleiche Problem, muss jedoch nicht 20.000 Linien sondern mindestens 200k ohne sichtbares Delay zeichnen. Wozu so viele Linien? Für einen sehr detailierten Plan, in den man hineinzoomen kann.
Ich habe auch mit WPF angefangen und mit kleinen Zeichnungen schnell Fortschritte gemacht. Aber bei steigender Größe / Deteilgrad der Pläne gibt es große Delays und die Anwendung nutzt mehrere hundert MB Arbeitsspeicher. (auch nachdem ich die Optimierungs-Tipps umgesetzt habe).
Deswegen habe ich mich mit DirectX beschäftigt, wofür es ja zumeist leider nur Anleitungen für C++ gibt. Ich habe etwas mit SharpDX und SlimDX experimentiert und kann nun 1mio Linien in ca einer Sekunde zeichnen, wobei die Anwendung keine 40MB im Arbeitsspeicher belegt.
Nun stehe ich vor der Umsetzung von Zooming, Scrolling aber finde nur Anleitungen und Foreneinträge zu 3D-Anwendungen. Ich benötige aber nur folgendes:
Was ich gefunden habe ist:
D2D.WindowRenderTarget.Transform
Damit kann ich vor dem Zeichnen tranformieren, aber nicht im nachhinein den Bildausschnitt wählen.
Habt ihr eine Idee wo ich dazu Informationen bekomme oder welches Buch ich mir dazu besorgen sollte?
Vielen Dank für eure Antworten.
Da es noch weitere Sonderfälle in der Anordnung gibt, werde ich das Problem nicht automatisch lösen. Der Anwender wird zwei Punkte wählen und bekommt dann über Pythagoras die Entfernung ausgegeben 😉
Wenn du beide Geraden als unendlich Lang betrachtest.
Dann scheinden sie sich auf Grund von Rundungsfehlern irgendwann.
Rundungsfehler wirst du aber immer drin haben.
Das ist mir klar 😉
Die Punkte können aber sonstwo liegen, deswegen kann ich daraus keine Geraden machen und hoffen, "dass es schon gutgehen wird" 8)
Vielen Dank, ihr habt natürlich von der Sache her Recht. Und ich werde es in meinen zukünftigen Anwendungen auch so umsetzen. Das Problem sind eben die "historisch gewachsenen" Teile und Komponenten die von Extern kommen. Habe auch noch Kandidaten gefunden, die auch nach dem Update noch mit der gleichen (Installer-)Version in der Registry stehen.
Ich wollte vermeiden, dass x Setups aufgerufen werden, dann merken, dass die Software bereits installiert ist und dann nochmal prüfen ob es der aktuelle Stand ist. Verbunden mit diversen Dialogen die geklickt werden müssen (nervt und birgt Fehlerpotenzial, der DAU läßt grüßen!).
Meine Vision war folgende:
-Auslesen der Registry, welche Software auf dem System läuft
-Abgleich mit meiner Liste der zu pflegenden Programme
-Wenn (Programm in Registry && Programm in Liste && Version unterschiedlich)
--> Dann deinstalliere alte Version und im Anschluß installiere neue Version (mit so wenig wie möglich Dialogen)
Vielen Dank schonmal für den Tipp mit SharpDX. Ließ sich ohne Probleme automatisch in der IDE installieren.
Ja ich habe mich unklar ausgedrückt. Ich habe mal ein Bild angehängt.
Mir liegen parallele Vektoren vor, deren minimalen Abstand ich berechnen möchte.
Über die Geradengleichung mit mx+n möchte ich nicht gehen, um die Sonderfälle (parallel zu den Koordinaten-Achsen) auszuschließen und weil durch Rundungsfehler die Vectoren in einem Winkel von 179.9xxxx Grad zueinander liegen und sich somit irgentwo treffen würden.
Auf meiner Suche nach einer geeigneten Bibliothek bin ich auf die Klasse Vector2 aus dem XNA-Framework gestoßen. link zur api
Ich habe aber gelesen, dass XNA "tot" sei, bei VS2013 ist es nicht in den Standartbibliotheken enthalten und meine Versuche das Framework nachzuinstallieren waren bisher auch nicht erfolgreich.
Ist euch eine Bibliothek bekannt, die mein Problem löst, ohne das ich selbst (fehlerbehafteten ^^) Code erzeugen muss? 😉
Vielen Dank!
Ich werde dann also nicht umher kommen, die Version des Installers bei jeder neuen Auslieferung/Update händisch zu erhöhen....
Zum Hintergrund meiner Frage. Ich schreibe gerade einen Updater für diverse Softwarekomponenten. Eigentlich wollte ich protokollieren welche Software-Versionen installiert sind, aber leider protokolliere ich über die Registry (@"Software\Microsoft\Windows\CurrentVersion\Uninstall") ja nur die Version der verwendeten Installer.
Somit ist es auch nicht möglich vor den Updates über die Registry zu überprüfen, ob die Version aktuell ist. Dazu müßte ich dann über die Version des Installers abgleichen (die ich nicht immer habe) 🤔
Moin,
für die Erzeugung des MSI-Paketes habe ich in VS2013 meiner Projektmappe ein "Visual Studio Installer - Setup Wizard"-Projekt hinzugefügt. Leider bin ich noch über zwei Probleme gestolpert:
Vielen Dank für Eure Hilfe! 😮