Laden...

Forenbeiträge von zeh-scharb Ingesamt 32 Beiträge

07.08.2015 - 12:49 Uhr

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;
        }

07.08.2015 - 09:59 Uhr

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:

  • Ich möchte in meiner Anwendung einen "Scripting-Bereich" zur Verfügung stellen. Der Benutzer kann in diesem Bereich eigenen Programm-Code schreiben, um Funktionen zu verändern / neu zu erstellen.
  • Dazu ist es notwendig, dass dem Benutzer Funktionen aus der Hauptanwendung bereitgestellt werden.

   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:

  1. Kompilieren
  2. Starten der Main
  3. Zugriff auf die laufende Instanz (Singleton) meiner durch DLL eingebundenen Funktionen, die vorher durch das Hauptprogramm gestartet wurden. Darüber werden z.b. Parameter im Scriptbereich eingebunden und Logging abgewickelt.

Was mir fehlt:

  • Ich möchte gerne Funktionen bereitstellen, die durch das Script aufgerufen werden können. Dazu muss das Script diese doch erben !?
  • Diese Funktionen sollen dem Benutzer via Autovervollständigung im Scripteditor angeboten werden (das sollte ich hinbekommen)

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 👍

07.07.2015 - 16:03 Uhr

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! 👍

07.07.2015 - 15:23 Uhr

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? 🤔

01.07.2015 - 10:08 Uhr

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?

25.06.2015 - 11:21 Uhr

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));

24.06.2015 - 14:14 Uhr

Die Version wird nicht mehr zum Download angeboten
http://sharpdx.org/download/

24.06.2015 - 12:26 Uhr

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.

12.06.2015 - 13:54 Uhr

Moin,
das sample kannte ich schon. Ist viel zu kompliziert für das was ich vorhabe und lässt sich auch nicht kompilieren 😦

11.06.2015 - 12:00 Uhr

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.

21.04.2015 - 07:53 Uhr

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 😁

20.04.2015 - 15:50 Uhr

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)

20.04.2015 - 15:12 Uhr

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.
😁

20.03.2015 - 15:05 Uhr

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?

20.03.2015 - 14:09 Uhr

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();
        }
    }
}

17.03.2015 - 10:02 Uhr

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

16.03.2015 - 15:43 Uhr

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;
        }
    }
}

05.03.2015 - 11:35 Uhr

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.

04.03.2015 - 17:28 Uhr

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?

04.03.2015 - 09:21 Uhr

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;
        }

03.03.2015 - 16:05 Uhr

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:

  • basicEffect.View/basicEffect.Projection verstehen und anpassen, um das Zoomen und Scrollen zu implementieren
  • Kontrolle über die "Update(GameTime gameTime)", damit diese nur ausgeführt wird, wenn etwas passiert. Momentan läuft die Grafikkarte auf Volllast und der Lüfter nervt 👅
27.02.2015 - 08:49 Uhr

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.

26.02.2015 - 17:08 Uhr

Habe es endlich geschafft die "Wpf Performance Suite" ans Laufen zu bekommen.
Dazu war es nötig:

  • Unter der Systemsteuerung die alte Version von "Microsoft Visula C++ 2010 Redistributable" deinstallieren damit das Windows SDK installiert werden kann und nicht im Setup abbricht
  • Den Patch für die Performance Suite ausführen, um den "Visual Profiler" zu fixen:
    link zum Pach

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>

26.02.2015 - 09:36 Uhr

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:

  • Einmaliges Übertragen der Linienkoordinaten auf die Grafikkarte
  • Verschieben des Blickfeldes horizontal / vertikal
  • Zooming
    Klingt jetzt nicht soooo exotisch, aber ich habe bisher nichts brauchbares gefunden.

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?

26.02.2015 - 09:16 Uhr

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 😉

23.02.2015 - 16:35 Uhr

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)

23.02.2015 - 16:16 Uhr

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)

  • Wenn keine Updates nötig sind ist die Sache nach einer Sekunde, ohne einen Dialog erledigt. Somit kann der Updater einmal pro Tag laufen / prüfen.
23.02.2015 - 15:55 Uhr

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.

23.02.2015 - 11:04 Uhr

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? 😉

23.02.2015 - 10:51 Uhr

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) 🤔

19.02.2015 - 11:03 Uhr

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:

  1. Für das Installer-Projekt wird unter Eigenschaften eine eigene Versionsnummer festgelegt. Diese wird dann nach der Installation auch in der Programmliste unter Systemsteuerung angezeigt. In meinem Programmfenster steht also eine andere Programmversion (Application.ProductVersion) als in der Registry.
    Ich habe bisher leider nicht herausgefunden, wie ich die Versionsnummer aus meinem Hauptprojekt übernehmen kann.
  2. Leider kann ich die Versionsnummer auch nicht händisch über die Eigenschaften des Setup-Projektes setzen, weil dort nur eine 3-stellige Kombination akzeptiert wird. Die Version des Hauptprogrammes ist hingegen 4-stellig.

Vielen Dank für Eure Hilfe! 😮