Laden...
Avatar #avatar-2333.jpg
Beauty myCSharp.de - Member
Student Thüringen Dabei seit 31.05.2007 79 Beiträge
Benutzerbeschreibung

Forenbeiträge von Beauty Ingesamt 79 Beiträge

29.12.2015 - 09:44 Uhr

Hallo MrSparcle und LaTino,

danke für Eure hilfreichen Antworten.

mit Linq hat das nicht viel zu tun.

Ich dachte das sei LINQ, weil ich die Schreibweise x => x.yy bisher nur von LINQ kenne.
Jemand mit Admin-Rechten könnte das Thema verschieben.

Was du brauchst, ist eine sortierte ObservableCollection.

In meinem Fall wollte ich keine Liste neu sortierten, sondern ein Element in eine bereits vorsortierte Liste eintragen.
Außerdem wollte ich in Sachen Technologie dazulernen.

Hier meine Lösung, die ich schon an mehreren Stellen verwenden konnte:


/// <summary>
/// Add an item to the related position of an already sorted list.
/// By the keySelector parameter you can define which property of the item should be used for comparison.
/// </summary>
/// <typeparam name="TSource">Type of the item, which to insert</typeparam>
/// <typeparam name="TKey">Property of the item, which is used for comparison</typeparam>
/// <param name="list">List where to add the item</param>
/// <param name="item">Item, which to add</param>
/// <param name="keySelector">Definition of the property which to choose for comparison</param>
public static void AddSorted<TSource, TKey>(this IList<TSource> list, TSource item, Func<TSource, TKey> keySelector)
{
    Int32 insertPosition = list.Count; // by default add to the end
    if (keySelector(item) is IComparable<TKey>)
    {
        for (Int32 i = 0;   i < list.Count;   i++)
        {
            if (((IComparable<TKey>)keySelector(item)).CompareTo(keySelector(list[i])) < 0)
            {
                insertPosition = i;
                break;
            }
        }
    }
    list.Insert(insertPosition, item);
}

11.12.2015 - 18:08 Uhr

verwendete Technologie: LINQ

Aufruf:


MyList.AddSorted(newItem, x => x.PROPERTY);

Ziel:
In die Liste MyList soll das Element newItem eingefügt werden.
Und zwar an die "richtige" Stelle. (alphabetisch bei String, numerisch bei Zahl, etc.)
Der Lambda-Ausdruck gibt an, welche Eigenschaft (PROPERTY) des Objekts mit CompareTo() verglichen werden soll.

Annahme:
Es handelt sich um eine vorsortierte Liste.

Beispiel:
In Liste { 1, 3, 5 } wird 4 hinzugefügt, dann wird sie zu { 1, 3, 4, 5 }.
(Bezogen auf die Werte in der angegebenen Eigenschaft.)

Lösungsansatz:
Eine Erweiterung des Listen-Klassentyps (z. B. ObservableCollection).


public static void AddSorted<TSource, TKey>(this IList<TSource> list, TSource item, Func<TSource, TKey> keySelector)
{
    Int32 insertPosition = list.Count; // by default add to the end
    if (item.PROPERTY is IComparable<TSource>)
    {
        for (Int32 i = 0;   i < list.Count;   i++)
        {
            if (list[i].PROPERTY.CompareTo(item.PROPERTY) > 0)
            {
                insertPosition = i;
                break;
            }
        }
    }
    list.Insert(insertPosition, item);
}

Mein Problem:
Wie schreibt man den Code, daß auf die im Lambda-Ausdruck angegebene Eigenschaft zugegriffen wird?
Der String PROPERTY im Code ist ein Platzhalter.

Ich habe schon eine Weile im Netz und im Forum gesucht. Und auch Herumprobiert. Leider fand ich keine Lösung.

Über eine hilfreiche Antwort würde ich mich freuen.

P.S.
SortedList<> ist für mich keine Option, da ich es für eine ObservableCollection brauche.
Außerdem möchte ich in Sachen Technologie dazulernen.

16.04.2012 - 02:15 Uhr

Hallo,

CMake kann Visual Studio-Dateien erzeugen.

Ich würde gerne wissen, mit welchem CMake-Script-Befehl man für den Release-Modus die Debug-Option "pdb-only" setzen kann.

Der Compiler-Befehl für Visual Studio müßte "/debug:pdbonly" sein.

Leide kenne ich mich mit CMake kaum aus.
Auch über eine Internet-Suche fand ich keine Info für diese Option im Zusammenhang mit CMake.

Kann mir jemand einen Tip geben?

09.02.2012 - 13:58 Uhr

Beschreibung:

Hier ist ein** kleines Werkzeug für Subversion (SVN)**.
Es bezieht sich auf das Datenformat von Subversion 1.7 (SQLite).
Quellcode zum Auslesen des alten Formats findet man in Reading the revision number of a local copy of a SVN repository.

Mein Code kann folgendes:

Auslesen der aktuellen Revisionsnummer:

SvnTool.GetRevisionNumber(String svnDirectory)

**Aktualisierung der Datei "ApplicationInfo.cs". **
Dabei wird die letzte Stelle der Versionnummer durch die aktuelle SVN Revisionnummer ersetzt.
Ergebnis: Die Versionsnummer der Anwendung (oder Bibliothek) beinhaltet die SVN-Revisionsnummer (z.B. 1.0.0.0 wird zu 1.0.0.666)

UpdateAssemblyInfo(String svnDirectory, String assemblyInfoPath)

Thanks to Wiktor Zychla, who published a demo code how to read out the the revision information from the Subversion database.

Quellcode:


using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.IO;

namespace SubversionTool
{

/// <summary>
/// Class to grabb the current SVN revision number.  <br/>
/// Also it's possible to update the "ApplicationInfo.cs" file to include the SVN revision number to the application or library version.<br/>
/// Note: Works only for the database format of Subversion version 1.7 and newer (SQLite).
/// </summary>
/// <remarks>
/// If you need support of Subversion 1.6 and below, look to URL 
/// http://netpl.blogspot.com/2011/10/reading-revision-number-of-local-copy.html 
/// </remarks>
private class SvnTool
{
    // Written by Wiktor Zychla (October 2011)
    // Source:  http://netpl.blogspot.com/2011/10/reading-revision-number-of-local-copy.html
    // Modified by Andreas Voigt (January 2012)
    // Source:  http://www.mycsharp.de/wbb2/thread.php?threadid=101541

    private const String databaseFile      = "wc.db";
    private const String pattern = "/!svn/ver/(?'version'[0-9]*)/";


    /// <summary>
    /// Grabb SVN information (Database format of Subversion version 1.7) <br/>
    /// If faild, it returns an empty String.
    /// </summary>
    /// <param name="svnDirectory">Absolute path to the Subversion directory (e.g. "C:\myProject\.svn") </param>
    public static String GetRevisionNumber(String svnDirectory)
    {
        String SvnSubfolder = svnDirectory;

        if (Directory.Exists(SvnSubfolder))
        {
            Int32 maxVer = 0;
            String EntriesFile = Directory.GetFiles(SvnSubfolder, databaseFile).FirstOrDefault();

            if (!String.IsNullOrEmpty(EntriesFile))
            {
                Byte[] fileData;
                try
                {
                    fileData = File.ReadAllBytes(EntriesFile);
                }
                catch (Exception)  // e.g. file not readable, because it's locked by an other thread
                {
                    return String.Empty;
                }
                String fileDataString = Encoding.Default.GetString(fileData);

                Regex regex = new Regex(pattern);

                foreach (Match match in regex.Matches(fileDataString))
                {
                    String version = match.Groups["version"].Value;
                    Int32 curVer;

                    if (Int32.TryParse(version, out curVer) == true)
                        if (curVer > maxVer)
                            maxVer = curVer;
                }

                if (maxVer > 0)
                    return maxVer.ToString();
            }
        }
        return String.Empty;
    } // GetRevisionNumber()





    /// <summary>
    /// Grabb and save the SVN revision number to the version information of the "AssemblyInfo.cs" file. 
    /// As result the last number of the application version is equal to the SVN revision. (e.g. "1.0.0.666")
    /// </summary>
    /// <param name="svnDirectory">Absolute path to the Subversion directory (e.g. "C:\myProject\.svn") </param>
    /// <param name="assemblyInfoPath">Absolute path to the file "AssemblyInfo.cs"</param>
    public static Boolean UpdateAssemblyInfo(String svnDirectory, String assemblyInfoPath)
    {
        // get current revision
        String revision = GetRevisionNumber(svnDirectory);
        if (revision == "")
        {
            Console.WriteLine("WARNING: Can't update information about Subversion revision."
                            + " (Failed to grabb from SVN database)");
            return false;
        }


        //---- update file "AssemblyInfo.cs" ----

        try
        {
            if (File.Exists(assemblyInfoPath) == false)
            {
                Console.WriteLine("WARNING: Can't update information about Subversion revision. "
                                + "(File 'AssemblyInfo.cs' not found)");
                return false;
            }

            Boolean doUpdate = false;

            // read file content
            FileStream assFileStream = new FileStream(assemblyInfoPath, FileMode.Open, FileAccess.Read);
            StreamReader assFileReader = new StreamReader(assFileStream);
            Encoding encodingType = assFileReader.CurrentEncoding;  // important for saving
            String assemblyInfoFileContent = assFileReader.ReadToEnd();
            assFileReader.Close();
            assFileStream.Close();


            //-- update "AssemblyVersion" entry --

            // build pattern for [assembly: AssemblyVersion("1.1.0.0")]
            String assemblyPattern_1 = @"(\[assembly: AssemblyVersion\(#\d+\.\d+\.\d+\.)\d+(#\)\])";
            assemblyPattern_1 = Regex.Replace(assemblyPattern_1, "#", "\"");  // replace symbols # by "

            // try to find pattern
            Match match_1 = Regex.Match(assemblyInfoFileContent, assemblyPattern_1);

            if (match_1.Success)
            {
                String replacement_1 = match_1.Groups[1] + revision + match_1.Groups[2];

                // check if content (revision number) changed
                if (match_1.Value != replacement_1)
                {
                    // update file content
                    assemblyInfoFileContent = assemblyInfoFileContent.Replace(match_1.Value, replacement_1);
                    doUpdate = true;
                }
            }


            //-- update "AssemblyFileVersion" entry --

            // build pattern for [assembly: AssemblyFileVersion("1.1.0.0")]
            String assemblyPattern_2 = @"(\[assembly: AssemblyFileVersion\(#\d+\.\d+\.\d+\.)\d+(#\)\])";
            assemblyPattern_2 = Regex.Replace(assemblyPattern_2, "#", "\"");  // replace symbols # by "

            // try to find pattern
            Match match_2 = Regex.Match(assemblyInfoFileContent, assemblyPattern_2);

            if (match_2.Success)
            {
                String replacement_2 = match_2.Groups[1] + revision + match_2.Groups[2];

                // check if content (revision number) changed
                if (match_2.Value != replacement_2)
                {
                    // update file content
                    assemblyInfoFileContent = assemblyInfoFileContent.Replace(match_2.Value, replacement_2);
                    doUpdate = true;
                }
            }



            // save to file (if needed)
            if (doUpdate)
            {
                FileStream assFileStream2 = new FileStream(assemblyInfoPath, FileMode.Truncate, FileAccess.Write);
                StreamWriter assFileWriter = new StreamWriter(assFileStream2, encodingType);
                assFileWriter.Close();
                assFileStream2.Close();
            }

        }
        catch (IOException e)
        {
            Console.WriteLine("WARNING: Can't update information about Subversion revision. "
                            + "(Problem at access to file 'AssemblyInfo.cs')\n    " + e.Message);
            return false;
        }

        return true;

    } // UpdateAssemblyInfo()


} // class SvnTool

} // namespace SubversionTool


Schlagwörter: SVN, Subversion, number, version, versionnumber revision, application, Versionsnummer, Programmversion, auslesen,
csharp, cs, csharp, C#, code, snippet, class

05.01.2012 - 13:54 Uhr

Auf einer anderen Website hatte ich Code gefunden, verbessert und dort veröffentlicht.

Der Rahmen hat dann auch abgerundete Ecken und einen zweiten Dekorationsrahmen.

Das Control ist auch flimmerfrei und ohne Pixelfehler (beim Verschieben/Größenänderung vom Fenster)
... Die Verbesserung konnte ich durch herbivores tolle Tutorials machen. Danke!!

Mein Code inklusive Anleitung zur einfachen Verwendung steht hier:
Changing border color of GroupBox

Leider gibt es auf der Seite keinen Direkt-Link zu meinem Beitrag.
Daher runterscrollen bis Improved version erscheint (fett/groß geschrieben)

Vielleicht kann es ja mal einer gebrauchen. 🙂

12.09.2011 - 17:58 Uhr

Ich habe gerade festgestellt, daß es bereits eine andere, kommerzielle Software mit dem Namen "Regex Studio" gibt.

Das könnte zu Verwechselungen führen oder gar eine Abmahnung zur Folge haben (vermute ich).
Darauf wollte ich nur mal kurz hinweisen.

Siehe hier:
www . regexstudio . com
(Den Link habe ich extra "verschleiert", damit die Leute dort nicht über die Browser-Rückreferenz direkt auf "unsere" Software aufmerksam werden.)

11.09.2011 - 03:23 Uhr

Ich habe es installiert und kurz ausprobiert.
Macht einen brauchbaren Eindruck - Danke (-:

Intensive Tests erfolgen später, wenn ich mal wieder was mit RegEx mache.

19.06.2011 - 23:40 Uhr

Ui, das ging ja schnell. Danke (-:

Deine verlinkte Website bezieht sich auf .NET 4.0.
Meine Anwendung kann ich aus Kompatibilitätsgründen nur mit .NET 3.5 benutzen. (Sonst gibt es Probleme mit mindestens einer externen Bibliothek/DLL-Datei.)
Aber mal sehen, vielleicht geht das auch mit .NET 3.5.

19.06.2011 - 23:25 Uhr

Hallo,

ich bin ziemlich verzweifelt. Seit Stunden versuche ich ein warscheinlich triviales Problem zu lösen.
Ich las in einem WPF-Buch, suchte im Internet, las in der MSDN-Doku, probierte herum, komme aber nicht weiter.

Was ich machen will:

In einer TreeView liste ich verschiedene Elemente auf.
So soll das dann aussehen.

Für meinen TreeView-"Prototyp" (siehe Bild) habe ich die Shapes direkt im jeweiligen Header definiert.


<TreeViewItem>
    <TreeViewItem.Header>
        <StackPanel Orientation="horizontal">
            <Rectangle Width="10" Height="10" Fill="LightGreen" Stroke="DarkGreen"  />
            <TextBlock>Seewolf</TextBlock>
        </StackPanel>
    </TreeViewItem.Header>
    <!-- ... weitere Elemente ... -->
<TreeViewItem>

Die Shape-Definitionen sind z.B.:


<Rectangle Width="10" Height="10" Fill="LightGreen" Stroke="DarkGreen" VerticalAlignment="Center" />
<Ellipse Width="10" Height="10" Fill="Blue" Stroke="DarkBlue" />
<Ellipse Width="10" Height="10" Fill="OrangeRed" Stroke="DarkOrange" />

Mein Ziel ist es, statt dessen Templates zu definieren.

Die Daten für jedes Element sind in einer speziellen Klasse gespeichert.
Dadurch kann über Binding z.B. auf die Eigenschaften "Name" und "NodeType" zugegriffen werden.

Das Template bindet den Namen ein, der angezeigt wird (z.B. "Obstacle 1").
Abhängig vom Inhalt der Variable "NodeType" soll für jedes Element ein bestimmtes Shape angezeigt werden.
Das könnte ich mit einem DataTrigger lösen, der das entsprechende Shape anzeigt.

Schritt 1 funktioniert:
Einbindung der Elemente erfolgt über ein Template.
Meine Daten werden geladen und im TreeView eingebunden.
Die Anzeige der Eigenschaft "Name" funktioniert.


<TreeView>
<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">

            <!-- HIER SHAPE EINFÜGEN ..... Rectangle/Circle abhängig vom Inhalt in {Binding NodeType} -->

            <TextBlock Text="{Binding Name}" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Die verschiedenen Shapes möchte ich als statische (oder besser logische?) Resource definieren. (z.B. in einem ResourceDirectory)


    <Rectangle x:Key="shape1" Width="10" Height="10" Fill="LightGreen" Stroke="DarkGreen" VerticalAlignment="Center" />
    <Ellipse   x:Key="shape2" Width="10" Height="10" Fill="Blue" Stroke="DarkBlue" />
    <Ellipse   x:Key="shape3" Width="10" Height="10" Fill="OrangeRed" Stroke="DarkOrange" />

Mein Problem:
Wie binde ich die verschiedenen Shape-Typen (Rectangle, Ellipse, etc.) in das Template ein?

Schon das einfache Einbinden eines Shapes als Resource bekomme ich nicht hin.
Also einfach nur sowas:


<TreeView>
<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">

            <!-- wie verweist man auf die Resource? -->
            <Rectangle VERWEIS="shape1" />  

            <TextBlock Text="{Binding Name}" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Weiteres Problem:
Rectangle, Ellipse, etc. sind verschiedene Typen (abgeleitet von "Shape").
Ich kann also nur auf den gleichen Typ verweisen.
Meine Lösungs-Idee dafür: Die Shapes in eine ViewBox verpacken.
Also etwa so:


<!-- Resourcen in ViewBox-Elementen -->
<ViewBox  x:Key="shape1">
    <Rectangle Width="10" Height="10" Fill="LightGreen" Stroke="DarkGreen" VerticalAlignment="Center" />
</ViewBox>
<ViewBox  x:Key="shape2">
    <Ellipse Width="10" Height="10" Fill="Blue" Stroke="DarkBlue" />
</ViewBox>
<ViewBox  x:Key="shape3">
    <Ellipse Width="10" Height="10" Fill="OrangeRed" Stroke="DarkOrange" />
</ViewBox>


<!-- Einbindung ins TreeView-Template -->
<TreeView>
<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">

            <!-- Verweis auf entsprechende ViewBox -->
            <ViewBox VERWEIS="shape1" />  <!-- aber wie? -->

            <TextBlock Text="{Binding Name}" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Wenn ich die Sache mit den Verweisen hinbekommen habe, dann kann ich das Ganze erweitern und über einen DataTrigger steuern, welches Icon (ViewBox mit Shape) für welches Element im TreeNode angezeigt wird.
Für DataTrigger habe ich ein nützliches Beispiel gefunden, was ich dann verwenden kann.

So, jetzt habe ich ganz schön viel geschrieben.
Es ist nicht immer einfach zu sagen, was man genau möchte.
Ich hoffe, das war verständlich.
Und ich hoffe, meinen langen Text hat jemand überhaupt gelesen. (-;

Hat jemand eine Idee, wie ich weiterkomme?

Ihr müßt keinen Roman schreiben (wie ich).
Es hilft bereits, wenn ich ein paar nützliche Schlagwörter, Code-Schnipsel oder Links bekomme.

P.S.
Das Bild von oben habe ich (als Backup) nochmal in den Anhang gepackt. Dann ist es immernoch zu sehen, wenn das obige irgendwann beim Bildhoster gelöscht wird.

08.06.2011 - 12:06 Uhr

Übrigens:
Für die Entwicklung und zum Test von regulären Ausdrücken gibt es nütliche Programme.
Eines ist der Regex Coach:
http://weitz.de/regex-coach

08.06.2011 - 12:02 Uhr

Ui, JAck30lena, Du bist ja ganz schön schnell (-:
Und auch Du, herbivore.
Stimmt, ich könnte auch auf MSDN suchen statt nur über Google.

Die XML-Parser-Klassen kenne ich.
Ich dachte nur, falls schon ein fertiger Parser für diese spezielle XML-Datei existiert, dann bräuchte ich das Rad nicht neu erfinden.

08.06.2011 - 11:56 Uhr

Oh, mir ist gerade eine Idee gekommen:

Wenn man mit Visual Studio kompiliert, wird eine Datei mit allen XML-Kommentaren automatisch erstellt. ( <projektName>.XML )
Ich könnte also auch daraus meine Infos extrahieren.
Kennt jemand eine Klasse, die diese XML-Datei ausliest und die Daten bequem zur Verfügung stellt?
Dann müßte ich keinen eigenen XML-Parser schreiben.

08.06.2011 - 11:47 Uhr

Hallo,

meine Frage in Kurzform:

Kann man den Inhalt von XML-Kommentaren per Quellcode auslesen?
Beispiel:


/// <summary>Das sind Beispiele</summary>
public enum BeispielEnums
{
    /// <summary>Beschreibung zu Eintrag1</summary>
    Eintrag1
}

Und dann z.B. auf den Inhalt von BeispielEnums.Eintrag1 zugreifen.

Gibt es dafür eine spezielle Klasse in .NET oder als externes Projekt?
Leider fand ich nichts hilfreiches im Internet. Vielleicht fehlt mir auch das richtige Schlagwort?

Hintergrund:

In meinem Projekt habe ich sehr viel in den XML-Kommentaren dokumentiert. Daraus kann man auch prima eine Hilfe-Datei erstellen lassen (msbuild / Sandcastle help file builder).
Meine Software wird jetzt (ohne Quellcode) rausgegeben werden und zu Doku-Zwecken möchte ich die XML-Kommentare einiger Enums, Strings, etc. in eine Text-Datei ausgeben.
Zwar könnte ich die Inhalte auch per Hand aus dem Quellcode kopieren, aber wenn sich später die XML-Kommentare ändere, dann müßte ich auch gleich die Doku überarbeiten. Besser wäre, wenn dieser Teil der Doku dynamisch generiert werden kann.

13.08.2010 - 20:56 Uhr

Sehr nützlicher Artikel - darüber habe ich auch weitere relevante Seiten gefunden.

Danke (-:

13.08.2010 - 02:30 Uhr

Mir geht es nicht um einzelne Mikrosekunden (oder gar Nanosekunden wie in einem anderen Thread), sondern nur darum, etwas genauer zu sein als wie die Rückgabe von DateTime.Now.Ticks.

Früher dachte ich blauäugig, die Zeitabfrage wäre wirklich so genau (etwa 100ns), aber später bemerkte ich eigenartige Effekte bei einem Programm. Ursache war, daß der Zeitwert von DateTime.Now.Ticks lange nicht so oft aktualisiert wird, wie der Name es vermuten läßt. Ich weiß die Aktualisierungsabstände nicht mehr. Vielleicht wurde etwa jede Millisekunde der Wert aktualisiert.

Der QueryPerformanceCounter ist eigentlich eine tolle Sache, aber die oben genannten (möglichen) Probleme machen mich etwas skeptisch.

12.08.2010 - 23:24 Uhr

Ah, Du meinst das:

die Stopwatch verwendet intern den QueryPerformanceCounter und somit dürfte keine Unterschied zwischen den beiden bestehen.

Theoretisch könnte es sein, daß die Stopwatch-Klasse schwankende CPU-Taktungen berücksichtigt. Vielleicht finde ich dazu was in der Doku.

Dennoch bleibt noch die Frage offen, ob es möglicherweise eine alternative (externe) Bibliothek für sowas gibt. Daher ist hochscrollen keine ultimative Lösung 😜

12.08.2010 - 21:58 Uhr

Oh, jetzt habe ich doch noch etwas interessantes gefunden:

Hallo Xqgene

wenn ich mit Stopwatch 10 mal in einer Schleife die Zeit für eine leere Anweisung messe, bekommt ich auf meinem Rechner exemplarisch folgende Ausgabe in Ticks (Jeder Tick stellt laut Doku ein Intervall von 100 Nanosekunden dar):

6
5
5
4
5
5
5
5
4
5

Also Schwankungen im Bereich von 200 Nanosekunden. Ich glaube das disqualifiziert auch die ansich nützliche Stopwatch für Messungen im Bereich von 0.1 - 5 nanosec. 😃

herbivore

Mit der Stopwatch-Klasse kann man also Zeitintervalle fast mit Tick-Genauigkeit messen.
Ich hoffe, da gibt es nicht so die Probleme wie beim QueryPerformanceCounter.

12.08.2010 - 21:21 Uhr

Hallo,

in einer Diskussion im Ogre-Forum (3D Grafikbibliothek) geht es auch gerade um FPS-Messungen (Bilder pro Sekunde) und FPS-Begrenzung (nicht schneller als xxx FPS rendern).
Als ich auf den QueryPerformanceCounter hinwies, bekam ich eine Antwort, daß das (heutzutage) Probleme verursachen kann:

Using the QueryPerformanceCounter functions can cause problems on multi-core CPUs, at least there were some serious problems in the past. I don't know if the .NET Stopwatch class is aware of the problem and contains a fix.

On most machines you should be fine using any of these methods. If you have strange effects, just remember that you might have to take care of these bugs.

A little more detail:
On multi-core CPUs the performance counter on different cores can have different values. If the scheduler changes your program flow to another core, you might get strange readings like large differences between calls. If you create a time delta every frame (currentTimeStamp - lastTimeStamp) and you get negative values, you just encountered this problem.

The easiest way is to use a background thread with an affinity mask that binds it to only one core. So the functions will always use the same performance counter and the problem is solved. You'll have to do this in C or C++ code, because .NET has its own internal scheduler that is independent of the system scheduler and you can't change the affinity mask in a reliable way.

More information about QueryPerformanceCounter problems can be found
>
and
>
.

Auch wenn die Zeitmessung ausschließlich auf einem CPU-Kern stattfindet, kann ich mir Probleme vorstellen, da sich bei modernen CPUs die Taktfrequenz dynamisch ändern kann. (Es sei denn, man liest ständig QueryPerformanceFrequency aus und beachtet Änderungen in den Zeitberechnungen. Trotzdem wären dann Zeitvergleiche komplizierter zu berechnen.)

Frage:
Gibt es vielleicht eine Bibliothek für präzise Zeitmessungen, die man bei .NET-Programmen einbinden kann und die oben genannten Probleme berücksichtigen? Ich hatte selber schon gesucht, aber nichts passendes gefunden.

06.07.2010 - 14:44 Uhr

Welches Projekt meinst Du genau?
Weder hier noch auf der Codeproject website finde ich ExtendedFileDialog.
Es gibt mehrere Projekte zu der Thematik.
Eine Übersicht meiner Recherchen habe ich weiter oben aufgelistet.

Das Projekt Extend OpenFileDialog and SaveFileDialog the easy way ist meiner Ansicht nach eine gute Wahl und (vor 6 Monaten) am aktuellsten. (Wie man es einbindet, habe ich über Deinem Beitrag beschrieben) Der Autor schrieb mir damals, daß er nach Erscheinen von Visual Studio 2010 das Projekt aktualisieren und u.a. meine genannten Bugfixe einbauen will. Das habe ich nicht kontrolliert.
Bei Problemen schaue am Besten in die Diskussion unter der Projektbeschreibung auf Codeproject. Da werden Probleme und teils auch Lösungen genannt. Da Windows 7 weit verbreitet ist, vermute ich, daß dort auch Lösungen veröffentlich wurden.
Wenn nicht, dann schreibe bitte auf der Projektseite Deinen Bugreport. Ober oder wie schnell jemand drauf antwortet, weiß ich nicht. Der Autor hatte mir damals recht schnell geantwortet.

Hast Du Deine Anwendung für 32 oder 64 bit compiliert?
Falls 64 bit - dann probier bitte interessehalber mal, ob der Fehler auch auftritt, wenn Du nach 32 bit compilierst.

26.04.2010 - 17:51 Uhr

Ich habe jemandem die Liste meiner Lesezeichen zum Thema **Icon-Websites **geschickt.
Hier nun eine Kopie für Interessierte. Einiges wurde schon genannt.
Ich glaube alle sind kostenlos, aber nicht alle sind für kommerzielle Software zulässig. Doch ich glaube das waren recht viele davon.
Beschreibungen habe ich weggelassen. Einfach durchklicken und schauen, ob brauchbar (-;

http://www.wincustomize.com/index.aspx?u=0
http://www.wilsonc.demon.co.uk/d10resourceeditor.htm
http://webdesignledger.com/tag/icons
http://www.famfamfam.com/lab/icons
http://www.famfamfam.com/lab/icons/silk/preview.php
http://pinvoke.com
http://www.x2studios.com/index.php?page=products&id=11
http://download.chip.eu/de/Vista-Icons-Pack-3.0_151414.html
http://commons.wikimedia.org/wiki/Crystal_Clear
http://commons.wikimedia.org/wiki/User:CyberSkull/Images/Crystal_Clear
http://sw-guide.de/webdesign-und-entwicklung/icon-sammlungen
http://www.freeiconsweb.com/free_icons.html
http://www.iconaholic.com
http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx
http://www.files32.com/downloads.asp?software=icons
http://tango.freedesktop.org/Tango_Icon_Library
http://www.iconarchive.com
http://www.iconbuffet.com
http://www.drweb.de/magazin/symbole-buttons-und-icons-zum-download
http://www.smashingmagazine.com/2007/05/24/freebies-round-up-icons-buttons-and-templates
http://www.glyfx.com/products/free.html
http://www.kde-look.org
http://vistaicons.com

Nützliche Icon-Suchmaschinen, wo man u.a. die gewünschte Lizenz eingeben kann:
http://www.iconlet.com
http://www.veryicon.com
http://www.iconlook.com
http://www.iconfinder.net

22.02.2010 - 15:06 Uhr

Die Lösung:

this.textBox1.SelectionStart = this.textBox1.Text.Length - 1;
this.textBox1.SelectionLength = 0;
this.textBox1.ScrollToCaret();

Da der Zeichen-Index mit 0 beginnt, ist das letzte Zeichen bei Stelle Length - 1 😁

11.02.2010 - 23:27 Uhr

Ich habe auch eine Gamepad-Ansteuerung für C# gesucht und ein interessantes Projekt gefunden:

SlimDX

What is SlimDX?

SlimDX is a free open source framework that enables developers to easily build DirectX applications using .NET technologies such as C#, VB.NET, and !IronPython. It is designed to be an efficient, simple, and lean wrapper that fully encompasses all of Microsoft's gaming and multimedia technologies and exposes them to managed code. All of the code is under the MIT/X11 license, and all content is under the Creative Commons Attribution-Share Alike license.

Kurz gesagt:
Eine praktische Bibliothek, mit der man u.a. recht einfach über DirectX auf Gamepads zugreifen kann.
Die MIT-Lizenz erlaubt auch die Einbindung in kommerzielle Projekte. (Soweit ich weiß. Sollte ich falsch liegen, bitte korrigieren.)

Im download Developer SDK sind auch Beispiele enthalten.
Eins bezüglich Gamepads ist im Verzeichnis
...\SlimDX SDK (August 2009)\Samples\DirectInput\Joystick
Es fragt die Zustände aller angeschlossenen Gamepads ab und zeigt sie in einer GUI.

Den Code vom Beispiel habe ich teilweise übernommen und kann jetzt mit meinem eigenen Programm mein Gamepad abfragen. Das "Einbauen" des Codes ging relativ schnell und funktioniert prima (-:

Download hier:
http://slimdx.org/download.php

11.02.2010 - 13:59 Uhr

Falls jemand Icons selber erstellen möchte - hier habe ich eine schöne Übersicht über kostenlose Icon-Programme gefunden:

http://mtechnologieinnovationn.blogspot.com/2009/11/er-gibt-deine-ikonen-mit-diesen-6.html

Für den Fall, daß es die Seite in Zukunft nicht mehr geben sollte, hier eine Übersicht der genannten Programme:

* Greenfish Icon Editor Pro
* IconFX
* Sib Icon Editor
* Stardock IconDeveloper
* aaICO Icon Editor
* LiquidIcon XP

Auf einer anderen Seite wurde von "Profis" ein open souce Vektor-Grafik-Programm empfohlen:
InkScape

In diesem Thema geht es zwar um fertige Icons, aber vielleicht ist diese Übersicht trotzdem für jemand hilfreich 😉

01.02.2010 - 12:47 Uhr

Genau das selbe würde ich auch gerne einstellen.
Zwar bei Visual Studio 2008, aber die Option wird vermutlich ähnlich heißen.

22.01.2010 - 02:43 Uhr

So, ich habe jetzt das oben genannte codeproject Extend OpenFileDialog and SaveFileDialog the easy way ausprobiert und meine Erweiterung dort eingebaut.

Auch dort mußte ich 2 Bugs fixen, die Ausnahmen geworfen haben g

Aber nun funktioniert es prima =)

Auch die Handhabung finde ich gut.
Man fügt das Projekt als UserControl hinzu und kann dann die GUI mit dem Designer von Visual Studio bequem gestalten.
Am Anfang wußte ich nicht wie man das UserControl hinzufügt. Die deutsche Übersetzung heißt Benutzersteuerelement. Wenn man das nicht weiß, muß man erst einmal eine Weile suchen (so wie ich).

So geht es:
Datei FileDlgExtenders.dll ins eigene Projekt kopieren und Referenz darauf hinzufügen.
Jetzt erst einmal neu kompilieren.

Dan geht man in den Projekt-Explorer und rechtsklickt auf das Projekt.
Dann Hinzufügen und dann Neues Element...
Links die Kategorie Windows Forms auswählen und rechts Geerbtes Benutzersteuerelement auswählen.
Unten Dateiname angeben und Hinzufügen klicken.
(Dann kommen bei mir 2 Warnungen - können ignoriert werden)
Im nächten Fenster auf Durchsuchen... klicken.
Dann die Datei FileDlgExtenders.dll referenzieren (die man vorher ins eigene Projekt kopiert).
Es erscheint anschließend in einer Liste, man wählt sie aus (anklicken) und klickt auf OK
Jetzt sollte das UserControl erscheinen.

Diverse Einstellungen kann man über die Eigenschaften machen - so wie bei einer Form.

Auf Grund (für mich) notwendiger Bugfixes habe ich den ganzen Quellcode aus dem Verzeichnis FileDlgExtenders in mein Projekt kopiert (und die Referenz auf die dll-Datei anschließend gelöscht).
So ist es möglich, das Projekt bequem zu debuggen.

Ich schreibe das so ausführlich, weil es vielleicht jemand gebrauchen könnte.

20.01.2010 - 03:56 Uhr

Ich habe mir mal angesehen, was es auf codeproject.com für mögliche C#-Alternativen für diesen Dialog gibt.

Customizing OpenFileDialog in .NET
Das Projekt wurde auch schon oben genannt. Leider hat es der Autor nicht mehr aktualisiert.
Verbesserungen und Bugfixes sind irgendwo in den vielen Kommentaren versteckt. (z.B. Unterstützung für neuere Windows-Versionen)
Letztes Update: 2006

Extend OpenFileDialog and SaveFileDialog the easy way
Ähnliche Funktionalität. Laut Beschreibung basiert es auf dem obigen Projekt Customizing OpenFileDialog in .NET, wurde aber erweitert und aktualisiert. Läuft auch auf Vista und Win7.
Das ist meine Empfehlung (Details dazu unten im übernächsten Beitrag).
Letztes Update: 2009

Extend OpenFileDialog and SaveFileDialog Using WPF
Ähnliches für WPF-Anwendungen
Letztes Update 2009

Full implementation of IShellBrowser
So wie es aussieht, hat jemand den Dialog (komplett?) nachprogrammiert und man kann den Dialog völlig frei gestalten (inkl. der "Standard-Elemente").
Letztes Update: 2009

Remote Control of Microsoft FileDialog Class (OpenFileDialog)
Beschreibt, wie man den "originalen" Dialog beeinflussen kann, um per Quellcode eine bestimmte Spalte zu sortieren (z.B. nach "Datum").
Letztes Update: 2009

FileDialogExtender
Hier geht es auch um die Erweiterung des originalen Dialogs, aber ich konnte auf den ersten Blick nicht erkennen, in welchem Umfang.
Letztes Update: 2004

Das ist nicht als Konkurrenz gedacht, sondern nur zur Information.
Vielleicht ist es ja brauchbar für andere Leute, die auch Probleme mit dem Projekt aus diesem Thread haben.
Eventuell findet man dort auch Problem-Lösungen und Anregungen.

Ergänzung:

Der Autor dieses Projekters (dr4g0n76) hat den Datei-Öffnen-Dialog komplett nachprogrammiert.
Siehe Thema CustomFileDialog

Der MSDN-Artikel Extensibility of Common Dialogs beschreibt die Grundlagen (Hooking etc.), wie man den Öffnen-Dialog erweitern kann.

19.01.2010 - 21:34 Uhr

Gibt es auch andere Leute, die dieses Projekt verwenden?

Wenn ja, wie sind die Erfahrungen? Gibt/Gab es da auch Probleme?

(Ausnahmen sind im Original-Code aber nicht zu erkennen, weil ein try/catch-Block alles abfängt. Bei einer Ausnahme schließt sich einfach das Dialog-Fenter.)

Langsam fange ich an zu verzweifeln ...

19.01.2010 - 21:24 Uhr

Ich verstehe das ganze nicht.

Jetzt nach dem Abendbrot habe ich wieder experimentiert.
Das zuletzt genannte Problem kann ich garnicht mehr reproduzieren.
Vorhin kam die Ausnahme ständig, wenn der Pfad der Datei (im Feld Objektname) anders war.

Meine Vermutung war, daß das vielleicht nur bei einem anderen Laufwerksbuchstaben auftritt. Aber auch da bekomme ich keine Ausnahme mehr. Es funktioniert korrekt.

Dennoch bekomme ich immer mal wieder eine AccessViolationException bei der im letzten Beitrag genannten Stelle.
Und zwar, wenn ich eine Datei gewählt habe und dann auf OK klicke.
Mal klappt es 2x problemlos, mal klappt es 10x problemlos. Dann kommt die Ausnahme.

An meinem eigenen Code liegt es scheinbar nicht (z.B. in Callback-Funktion).
Bei einem Versuch habe ich ihn auskommentiert, bei einem anderen Versuch habe ich das Originale Beispiel-Programm verwendet (mit der Modifikation, daß Ausnahmen nicht abgefangen werden).

Noch ein neues Problem fiel mir auf:

Wenn das Auswählen einer Datei erfolgreich war, dann kann man den Dateiname (inkl. Pfad) über die Eigenschaft OpenFileDialog.SelectedPath abfragen.

In seltenen Fällen liefert der Wert "Müll" zurück.

1)
Es kam vor, daß der Pfad abgeschnitten war
z.B. (G:\OgreS

Es kam vor, daß kryptische Zeichen enthalten waren.
Entweder nach einem abgeschnittenen Pfad (siehe Anhang) oder mitten drin.

Das war aber nicht abhängig von der gewählten Datei.
Denn die Dateien, bei der die Fehler auftraten, ließen sich bei mehreren Wiederholungen problemlos ermitteln. (SelectedPath lieferte dann den richtigen Wert)

Der Wert wird intern über diesen Code ermittelt (Datei OpenFileDialog.cs):


public string SelectedPath
{
	get { return Marshal.PtrToStringUni( m_ptrFileNameBuffer ); }
}
19.01.2010 - 18:45 Uhr

Jetzt habe ich eine reproduzierbare Ursache gefunden, eine AccessViolationException zur Folge hat.

Sie tritt auf, wenn man im Feld "..." des Dialoges eine Datei inklusive Pfad einfügt und das aktuelle Verzeichnis nicht dem Pfad entspricht, die in der Datei angegeben ist (und anschließend OK geklickt wird).

Beispiel:
aktuelles Verzeichnis = "C:\Eigene Bilder";
Datei mit Pfad = "++C:\pfad\woanders++datei.txt"

Wenn der Datei-Pfad auch dem aktuellen Pfad entspricht, gibt es keine Probleme.

Die Ausnahme tritt in der Datei OpenFileDialog.cs auf.


private bool ShowInternal()
{
    Boolean m_catchExceptionsOfShow = false;  // TEST
    bool bSuccess = false;

    if (m_catchExceptionsOfShow)
    {
        try
        {
            bSuccess = NativeMethods.GetOpenFileName(ref this.m_OpenFileName);
            return bSuccess;
        }
        catch (Exception ex)
        {
            return bSuccess;
        }
    }
    else  // don't catch exceptions
    {
        return NativeMethods.GetOpenFileName(ref this.m_OpenFileName);  // HIER AccessViolationException
    }
}

Wo die programmiertechnische Ursache nun liegt, weiß ich nicht. Doch es würde mich freuen, wenn das Problem behoben wird.

P.S.
Auch dieses Problem konnte ich nur finden, weil ich in der modifizierten Methode ShowInternal() keine Ausnahmen kommentarlos abfange. (So wie in der ursprünglichen Version)

Ergänzung:
Die Variable m_OpenFileName kann ich vor dem Aufruf von GetOpenFileName(...) nicht einfach manipulieren, um den Pfad zu korrigieren.
Sie ist ein Struct, das keinen String enthält. Statt dessen sind nur die Datentypen Int32, IntPtr und ein OfnHookProc enthalten.

18.01.2010 - 21:05 Uhr

Hier eine kleine Ergänzung/Übersicht zum Thema Byte Order Mark.
Diese Infos habe ich aus der Wikipedia (hier).

    Bytefolge         Kodierung

    EF BB BF ........ UTF-8 
    FE FF ........... UTF-16 Big Endian
    FF FE ........... UTF-16 Little Endian
    00 00 FE FF ..... UTF-32 Big Endian
    FF FE 00 00 ..... UTF-32 Little Endian

Falls es jemand braucht und zu faul zum Schreiben ist - hier die Quellcode-Definition:

Byte[] bomUTF_8      = {0xEF, 0xBB, 0xBF};
Byte[] bomUTF_16_BE  = {0xFE, 0xFF};
Byte[] bomUTF_16_LE  = {0xFF, 0xFE};
Byte[] bomUTF_32_BE  = {0x00, 0x00, 0xFE, 0xFF};
Byte[] bomUTF_32_LE  = {0xFE, 0xFF, 0x00, 0x00};
15.01.2010 - 20:03 Uhr

Aha, durch meine zuletzt genannte Erweiterung habe ich wieder ein Problem entdeckt.

Es tritt auf, wenn man auf eine Verlinkung doppelklickt (*.lnk-Datei) und die Dialog-Eigenschaft DereferenceLinks auf true steht.
Dann soll der Dialog in das Ziel-Verzeichnis springen und dessen Inhalt anzeigen.
Dies funktioniert grundsätzlich.
Das Problem tritt erst dann auf, wenn man zuvor eine andere Datei angeklickt hat und danach erst die Verlinkung doppelklickt.

Dabei wird nämlich die Callback-Funktion OpenFileDialog.SelectionChanged aufgerufen und ein ungütiger Pfad als Argument übergeben.
Dieser ist zusammengesetzt aus dem Zielpfad der Verlinkung UND dem Dateinamen der zuvor ausgewählten Datei.

Das tritt nur selten auf und läßt sich leicht beheben, aber wenn man das nicht weiß und beachtet, dann kann das zu einer Ausnahme führen.
Im Normalfall wird die Ausnahme abgefangen (siehe try/catch-Block meises letzten Beitrags).
Für den Nutzer ist es aber irretierend, weil sich der Dialog einfach schließt.

Am Anfang der Callback-Funktion OpenFileDialog.SelectionChanged ist es also ganz wichtig zu prüfen, ob der Pfad valide ist.


// Callback-Funktion für OpenFileDialog.SelectionChanged
private void ofd_SelectionChanged( string _sPath )  
{
    if (!File.Exists(_sPath) && !Directory.Exists(_sPath))
        // abort if no valide path 
        // (this happens in seldom special cases) 
        return;

    // ...
}

Leider ist (nach meinem Kenntnisstand) keine Möglichkeit vorhanden, die Pfad-Gültigkeit innerhalb der Klasse OpenFileDialog zu prüfen, bevor die Callback-Funktion aufgerufen wird. Die Callback-Funktion scheint nämlich direkt an einen externen Aufruf geknüpft zu sein.

[DllImport("ComDlg32.dll", CharSet = CharSet.Unicode)]
internal static extern bool GetOpenFileName( ref OpenFileName ofn );
15.01.2010 - 17:45 Uhr

In der Callback-Funktion OpenFileDialog.SelectionChanged kann der Nutzer eigenen Code einfügen (z.B. Vorschaubild aktualisieren).
Wenn in diesem Code eine unbehandelte Ausnahme entsteht, dann wird sie durch diesen Code in Datei OpenFileDialog.cs abgefangen:


public bool Show()
{
        SetDialogFlags();

        return ShowInternal();
}

private bool ShowInternal()
{
    bool bSuccess = false;
    try
    {
        bSuccess = NativeMethods.GetOpenFileName(ref this.m_OpenFileName);
        return bSuccess;
    }
    catch (Exception ex)  // HIER abgefangen
    {
        return bSuccess;
    }
}

Eigentlich eine gute Sache.
Mich hat das aber des öfteren irretiert.
Wenn ich bestimmte Dateien angeklickt habe, dann ist der Dialog einfach zugegangen und ich habe nicht verstanden warum.
Erst beim zeilenweise Debuggen habe ich die Ursache gefunden. (das catch() in Datei OpenFileDialog)

Bei mir war es u.a. ein Fehler beim XML parsen.
Das sollte ich natürlich selbst abfangen (per try/catch), aber bei meinen kleinen Dialog-Experimenten habe ich das nicht getan.
Gut wäre gewesen, wenn ich dann als Programmierer gesehen hätte, daß es eine Ausnahme gab. Am Besten an der Stelle, wo sie aufgetreten ist.

Das brachte mich auf folgende Ideen:

1.
Speicherung der Ausnahme (Variable ex) in einer Klassen-Variable, die man abfragen kann, wenn OpenFileDialog.Show() ein false zurückliefert.

Exception OpenFileDialog.ExceptionOfShow  // Eigenschaft

2.
Die Möglichkeit einzustellen, ob der oben zitierte try/catch-Block verwendet wird.
Etwa über die Eigenschaft

Boolean OpenFileDialog.CatchExceptionsOfShow

Die Eigenschaft wäre standardmäßig auf true.

Hier der erweiterte Code, wie ich das machen würde:

private bool ShowInternal()
{
    Boolean m_catchExceptionsOfShow = false;  // TEST
    bool bSuccess = false;

    if (m_catchExceptionsOfShow)  // check mode
    {
        try
        {
            bSuccess = NativeMethods.GetOpenFileName(ref this.m_OpenFileName);
            return bSuccess;
        }
        catch (Exception ex)
        {
            return bSuccess;
        }
    }
    else  // don't catch exceptions
    {
        return NativeMethods.GetOpenFileName(ref this.m_OpenFileName);
    }
}

Alternativ könnte man es auch die Möglichkeit einbauen, daß die Ausnahmen nur im Release-Modus abgefangen werden und bei Debug-Modus "durchlassen".
Einstellen könnte man das so:

enum ExceptionOfShowModes = { Catch, NoCatch, CatchInDebugMode }
ExceptionOfShowModes OpenFileDialog.CatchExceptionsOfShow

Irgendwo habe ich gelesen, daß man im Quellcode abfragen kann, ob das laufende Programm im Debug oder Release-Modus compiliert wurde.

Was haltet Ihr davon, wenn ich diese Erweiterungen in die Veröffentlichung einbaue?

15.01.2010 - 13:32 Uhr

Ich habe nochmal in der Doku von Visual Studio 2008 nachgesehen.

Ruft das Ausgangsverzeichnis ab, das im Dateidialogfeld angezeigt wird, oder legt dieses fest.

Für die Eigenschaft FileDialog.InitialDirectory steht kein Hinweis darauf, daß die auf bestimmte Windows-Versionen beschränkt wäre. Im Beispielcode der Doku wird "C:\" vorgegeben.
Ich halte für sehr sinnvoll, daß man das Start-Verzeichnis angeben kann.
Beim "normalen" Dialog verwende ich das auch und es funktioniert.

Bei der Registrierung habe ich mal reingesehen.
Es ist interessant, was bei OpenSaveMRU alles für Verzeichnisse gespeichert sind. Teilweise uralte Pfade g

P.S.
Schön zu sehen, daß hier auch noch andere mitlesen und Anregungen geben 🙂

15.01.2010 - 03:25 Uhr

Leider habe ich wieder ein Problem festgestellt.

Die Angabe der Eigenschaft InitialDirectory wird ignoriert.
Habe es mit einer relativen, aber auch mit einer globalen Pfad-Angabe versucht.
Diese sind auch gültig - habe das getestet.

ScenePath = "..\\..\\Test-Dateien"; // relativer Pfad
openFileDialog.InitialDirectory = ScenePath;
Boolean test = Directory.Exists(openFileDialog.InitialDirectory); // Verzeichnis vorhanden? --> ja

Im Quelltext habe ich gesehen, daß diese Angabe zwar in der Klasse gespeichert wird, aber ansonsten nirgendwo verwendet wird.

Statt dessen ist das Start-Verzeichnis des Dialoges immer "Eigene Bilder".
Ob das irgendwo im Quellcode definiert wurde, konnte ich nicht rausfinden. Wäre aber möglich.

Die Behebung dieses Problems halte ich für sehr wichtig.

15.01.2010 - 01:56 Uhr
bool bShow = openFileDialog.Show();

Was genau bedeutet der Rückgabewert?
Daß eine Datei (oder mehrere) gewählt wurden und dann OK gelickt wurde?
(entsprechend DialogResult.OK)

Aus dem Code werde ich nicht schlau.
Ein XML-Kommentar dazu wäre praktisch. (da kann ich dann einfügen)

Im "originalen" Dialog gibt es keine Methode namens Show().
Statt dessen wird es da so gemacht:

DialogResult result = ofDialog.ShowDialog();
// oder in dieser Weise:
if (ofd.ShowDialog() == DialogResult.OK)

Der Rückgabewert ist ein enum.

13.01.2010 - 23:41 Uhr

Wegen dem Filter-Problem habe ich etwas eigenartiges festgestellt.

Bei dem Test-Programm funktioniert die Auswahl richtig.
Der Filter-String ist darin so definiert:

"Picture files (*.JPG;*.GIF;*.PNG)\0*.jpg;*.gif;*.png\0\0"

Laut MSDN-Doku muß man aber ein Pipe-Symol als Trennzeichen verwenden statt \0 wie bei Dir.
Was mich auch wundert ist, daß am Ende Deines Filters nochmal "\0\0" steht.

So steht es als Beispiel in der Doku:

filter = "All files (*.*)|*.*";

Im Code habe ich nachgesehen, was mit der Filter-Variable passiert.
Sie wird nur in einer Zeile verwendet (Datei NativeMethods.cs, Methode InitFileDialog(...)):

m_OpenFileName.lpstrFilter = Marshal.StringToCoTaskMemUni(_sFilter);

Das Ergebnis wird in m_OpenFileName.lpstrFilter gespeichert (Typ IntPtr), aber nicht mehr im Quelltext der Klasse benutzt.

Von Marshaling habe ich keine Ahnung.
Kann also selber nicht rausfinden, wo der Fehler liegt.

Was mir aber auffiel ist, daß im Stuct OpenFileName die ähnlich aussehende Variable lpstrCustomFilter definiert ist, aber nie verwendet wird. Ob das was damit zu tun hat, weiß ich nicht.

Eine schmutzige Lösung wäre, intern die Filter-Eingabe mit einem regulären Ausdruck zu modifizieren. Also Pipes zu "\0" umwandeln und ggf. "\0\0" anzuhängen.
Besser wäre es natürlich, die echte Ursache zu finden und zu beheben.

13.01.2010 - 18:42 Uhr

Mir ist wieder etwas aufgefallen. Zum Glück aber kein Fehler (-;
Beim Screenshot im ersten Beitrag belegt das eingefügte Panel die komplette rechte Seite. Bei der CustomDialogs-Klasse ist die Höhe reduziert, da sich das Panel(?) mit Dateiname und Dateityp bis ganz rechts streckt.
In Worten läßt sich das nicht so gut beschreiben. Deshalb habe ich ein Bild erzeugt und angehangen. Die roten und blauen Rahmen markieren dabei die Panel-Flächen.

Für meine Software fände ich gut, wenn ich die ganze rechte Hälfte zur Verfügung habe. Das ist vermutlich von Nutzer zu Nutzer verschieden.
Daher wäre eine Option dafür ganz praktisch (und nutzerfreundlich).
Beispielsweise durch folgende Eigenschaft:

public VerticalPanelScaleProp OpenFileDialog.VerticalPanelScale   // Eigenschaft änderbar
public enum VerticalPanelScaleProp = { MaxHeight, AboveFilenamePanel }  // mögliche Werte

Wie man das im Quelltext ändert, habe ich nicht so recht rausgefunden.
Vielleicht in Methode MyHookProc(...) an folgender Stelle? Wenn ja, wie?


case WindowMessage.InitDialog:
{
	IntPtr ptrHWndParent = NativeMethods.GetParent( ptrHWnd );
            NativeMethods.SetParent(this.m_UserControl.Handle, ptrHWndParent);
13.01.2010 - 18:02 Uhr

Nun habe ich ein weiteres Problem festgestellt.
Und zwar bezogen auf die Eigenschaft Filter.

Bei Dateityp steht nur der Filter-Ausdruck, der als String definiert ist.
In der weiteren Auswahl sind "komische" Zeichen zu sehen.

Beispiel:

filter = "All files (*.*)|*.*";

(Bild ist im Anhang)

Dabei fällt mir noch eine Kleinigkeit auf:
Beim "normalen" Dialog steht links unten Dateiname und Dateityp.
Im erweiterten Dialog steht statt dessen Objektname und Objekttyp.
Das ist zwar nichts schlimmes, aber ich wollte das mal erwähnen.

Ändern konnte ich das nicht, da die Strings Objektname und Objekttyp nirgendwo im Quelltext zu finden sind.
So wie ich verstanden habe, tut die Klasse OpenFileDialog nur den normalen Dialog erweitern. Warum dann die Strings anders heißen, ist mir unklar.
In den Screenshots vom ersten Beitrag ist der Fehler scheinbar nicht vorhanden.

13.01.2010 - 17:16 Uhr

So, nach einiger Suche fand ich jetzt doch die Lösung für mein Panel-Problem.
Für das Formular, in dem ich das Panel definiert habe, muß ich nur ein kleines Attribut ändern.
Und zwar .TopLevel = false.
Dann erscheint kein leeres Formular mehr.

Ein Panel, das man im "Designer" vom Visual Studio erstellt hat, kann man also so einbinden:


// Panel extrahieren, welches in einer (unsichtbaren) Form eingebettet ist
PanelForm panForm = new PanelForm();
panForm.TopLevel = false;
panForm.Show();
Panel panel = panForm.cvPanel;

// Öffnen-Dialog
String filter = "All files (*.*)|*.*";
CustomizableDialogs.OpenFileDialog openFileDialog = new CustomizableDialogs.OpenFileDialog("*", "", filter, panel);
openFileDialog.SelectionChanged += new CustomizableDialogs.OpenFileDialog.SelectionChangedHandler(ofd_SelectionChanged);
bool bShow = openFileDialog.Show();

// unsichtbare Form (ink. Panel) wieder löschen
panForm.Dispose();

Leider gab es beim Schließen des Dialog-Fensters wieder mehrfach eine Ausnahme an dieser Stelle in Datei OpenFileDialog.cs:

public new void Dispose( bool disposing )
{
	if( disposing )
	{
t		GC.SuppressFinalize( this );
	}

	Marshal.FreeCoTaskMem( this.m_ptrFileNameBuffer );  // HIER AUSNAHME AccessViolationException
	Marshal.FreeCoTaskMem( this.m_ptrFileTitleBuffer );
	Marshal.FreeCoTaskMem( this.m_ptrIpTemplate );
}

Und es gab eine Ausnahme hier:

public bool Show()
{
        SetDialogFlags();

        return NativeMethods.GetOpenFileName(ref this.m_OpenFileName);  // HIER AUSNAHME AccessViolationException
}

Schade, daß der Öffnen-Dialog so instabil zu sein scheint.
Als Notlösung könnte man einen try/catch Block um die betreffenden Stellen machen.
Besser wäre aber, die Ursache(n) zu finden und zu beheben. Allerdings habe ich bei diesen Ausnahmen keine Ahnung, woran das liegen kann.

07.01.2010 - 17:47 Uhr

Update: Dieses Problem ist gelöst.
Deshalb ist der Text jetzt in grauer Farbe.

Nun eine praktische Frage:

Ich habe ein Test-Programm erstellt, bei dem im Öffnen-Dialog ein Panel mit mehreren Elementen angezeigt werden soll (derzeit 16 Stück).

Da eine GUI-Gestaltung per Quellcode unbequem ist, habe ich in Visual Studio ein neues Formular erstellt und in diesem mein Panel grafisch per Designer gestaltet.
Die Einbindung funktioniert, indem ich das Formular erstelle und die Panel-Referenz an den Öffnen-Dialog übergebe:

PanelForm panForm = new PanelForm();
panForm.Show();
Panel panel = panForm.cvPanel;

String filter = "All files (*.*)|*.*";
CustomizableDialogs.OpenFileDialog openFileDialog = new CustomizableDialogs.OpenFileDialog("*", "", filter, panel);
openFileDialog.SelectionChanged += new CustomizableDialogs.OpenFileDialog.SelectionChangedHandler(ofd_SelectionChanged);
bool bShow = openFileDialog.Show();

panForm.Dispose();

Grundsätzlich klappt das. Das Problem ist aber, daß ich das "Hilfs-Formular" nicht nur erstellen, sondern auch anzeigen muß. Ansonsten enthält die Panel-Referenz keinen Inhalt.

Erfolglos war auch dieser Versuch (zeigt leeres Panel im Öffnen-Dialog):

PanelForm panForm = new PanelForm();
panForm.CreateControl();
panForm.cvPanel.CreateControl();

Wenn ich es mit einem versteckten Formular versuche, dann wird ein leeres Fenster angezeigt.

PanelForm panForm = new PanelForm();
panForm.Visible = false;
panForm.Show();

Hat jemand eine Idee dazu?

Anmerkung:
Eigentlich kann man das Panel mit dem Designer von Visual Studio grafisch erstellen und einfach den generierten Quellcode kopieren. Allerdings ist das nicht sehr nutzerfreundlich, wenn man später Änderungen am Layout machen möchte.

Anmerkung 2:
Meine Frage weicht ein kleines bischen vom eigentlichen Thema ab, aber ich habe bewußt keinen neues Thema aufgemacht. Es kann nämlich durchaus sein, daß jemand den erweiterten Öffnen-Dialog benutzt und das selbe Problem hat mit der Panel-Erstellung. Dann finde ich sinnvoll, wenn hier gleich die Lösung steht.

07.01.2010 - 14:48 Uhr

Ich habe mir heute nochmal das Projekt angesehen.

Wegen dem Verlinkungs-Problem habe ich nicht nur das default-Flag geändert, sondern eine kleine Methode geschrieben, die die default-Flags so setzt, wie sie beim "originalen" Öffnen-Dialog sind:

        private void SetDefaultFlags()
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            m_bCheckFileExists  = ofd.CheckFileExists;
            m_bMultiSelect      = ofd.Multiselect; ;
            m_bReadOnlyChecked  = ofd.ReadOnlyChecked;
            m_bCheckPathExists  = ofd.CheckPathExists;
            m_bDereferenceLinks = ofd.DereferenceLinks;
            m_bRestoreDirectory = ofd.RestoreDirectory;
		    m_bShowHelp         = ofd.ShowHelp;
            m_bShowReadOnly     = ofd.ShowReadOnly;
            m_bSupportMultiDottedExtensions = ofd.SupportMultiDottedExtensions;
            m_bValidateNames    = ofd.ValidateNames;
            ofd.Dispose();
        }

Diese wird am Anfang von InitFileDialog() aufgerufen.
So können wir sicher sein, daß die Flags dem Original entsprechen (auch falls sich das in Zukunft ändern sollte, was ich weniger denke).
Im Anhang ist die modifizierte Datei.

Wegen dem Problem mit der Größenänderung habe ich folgendes rausgefunden.
Die Größe der erweiterten Fläche (im Beispiel das skalierte Bild) wird durch die Methode FindAndResizePanels() berechnet.
Allerdings wird sie scheinbar nur aufgerufen, wenn man der Dialog geöffnet wird oder wenn man eine Datei (bzw.) Verzeichnis markiert.
Was fehlt, ist ein Aufruf dieser Methode sobald der Nutzer die Größe des Dialog-Fensters ändert.
Wo man den zusätzlichen Methoden-Aufruf einbauen muß, habe ich leider nicht rausgefunden. Möglicherweise in der Methode MyHookProc().

Beim experimentieren fiel mir noch ein möglicherweise unerwünschter Effekt auf.
Wenn man die Größe des Öffnen-Dialoges ändert (und anschließend eine Datei bzw. ein Verzeichnis markiert), dann ändert sich auch die Größe des eingebetteten Panels (erstellt durch Nutzer).
Die Größe des Panels wird immer so gesetzt, daß es halb so breit ist, wie das Dialog-Fenster.

Für eine Bild-Vorschau kann das praktisch sein (durch automatische Skalierung).
Aber wenn das Panel eine feste Größe haben (und behalten) soll, dann geht das nicht.
Sinnvoll wäre das für eine Vorschaubild-Anzeige mit fester Größe oder zum Anzeigen von anderen Informationen (z.B. Text, Icons).

Daher mein Vorschlag:
Den Öffnen-Dialog um Eigenschaften erweitern, mit denen man das gewünschte Verhalten einstellen kann.
z.B.

public Boolean OpenFileDialog.FixedPanelSize
// wenn true, dann bleibt Panel-Größe unverändert

public Byte OpenFileDialog.PercentualPanelWidth   
// z.B. 50 für halbe Fläche, 33 für ein Drittel der Fläche;
// gültiger Bereich: 1 .. 99

public Int32 OpenFileDialog.DialogSize
// die Größe des gesamten Dialog-Fensters vorgeben
// standardmäßig ist das sehr klein

public event OpenFileDialog.SizeChanged
// eine Möglichkeit, daß der Nutzer sein Panel entsprechend anpassen kann,
// wenn sich die Größe des Dialog-Fensters ändert

Sinnvoll fände ich auch eine Option, mit der man den Panel auch unter der Dateiauswahl-Box positionieren kann. (z.B. für Ausgabe langer Textzeilen)

public enum PanelPositions = { Bottom, Right }   // mögliche Werte (ev. auch oben/links)
public PanelPositions OpenFileDialog.PanelPosition   // Eigenschaft änderbar

Ich vermute, das verarbeiten dieser Einstellungen müßte in der Methode FindAndResizePanels() eingebaut werden.

Manchmal bekomme ich beim dem beigelegten Beispielprogramm eine AccessViolationException.
Gerade eben war das beim Markieren einer Datei.
Der Debugger zeigt die Ausnahme in der Zeile bool bShow = openFileDialog.Show();
Leider zeigt er nicht, so genau in der Dialog-Klasse.
Hier einige Details - eventuell helfen die bei der Fehlersuche.

Message:
"Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist."

Source:
"ExtensibleDialogs"

Trace:
   bei CustomizableDialogs.NativeMethods.GetOpenFileName(OpenFileName& ofn)
   bei CustomizableDialogs.OpenFileDialog.Show() in c:\OgreSDK\projekte\CustomizableDialogs (Datei öffnen mit Vorschau)\CustomizableDialogs\ExtensibleDialogs\OpenFileDialog.cs:Zeile 315.
   bei TestTemplateFileDialog.MainForm.buttonChooseFile_Click(Object sender, EventArgs e) in c:\OgreSDK\projekte\CustomizableDialogs (Datei öffnen mit Vorschau)\CustomizableDialogs\TestClient\MainForm.cs:Zeile 124.
   bei System.Windows.Forms.Control.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   bei System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   bei System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
   bei System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
   bei System.Windows.Forms.Control.WmCommand(Message& m)
   bei System.Windows.Forms.Control.WndProc(Message& m)
   bei System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   bei System.Windows.Forms.ContainerControl.WndProc(Message& m)
   bei System.Windows.Forms.Form.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   bei System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   bei System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
   bei System.Windows.Forms.Control.DefWndProc(Message& m)
   bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   bei System.Windows.Forms.Control.WndProc(Message& m)
   bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
   bei System.Windows.Forms.Button.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.Run(Form mainForm)
   bei TestTemplateFileDialog.MainForm.Main() in c:\OgreSDK\projekte\CustomizableDialogs (Datei öffnen mit Vorschau)\CustomizableDialogs\TestClient\MainForm.cs:Zeile 97.
   bei System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   bei System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
   bei System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
   bei System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
   bei System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
   bei System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
   bei System.Activator.CreateInstance(ActivationContext activationContext)
   bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
   bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   bei System.Threading.ThreadHelper.ThreadStart()

Die hier vorgestellte Klasse heißt OpenFileDialog, also genauso wie das "Original".
Um Verwechslungen zu vermeiden würde ich vorschlagen, die Klasse umzubenennen. Vielleicht zu ExtOpenFileDialog oder OpenFileDialogExtended

Natürlich kann man sich selber die Klasse so anpassen, wie man sie gerne hätte. Dennoch denke ich, daß es sinnvoll wäre, die genannten Optionen einzubauen. Dann ist sie flexibler einsetzbar und der Nutzer (Programmierer) muß nicht erst im Quellcode nach Stellen suchen, wo man das ändern kann.

Anmerkung: Ich möcht dem Autor nicht reinreden, sondern mache nur Vorschläge 😉

06.01.2010 - 18:29 Uhr

Wegen dem Verlinkungs-Problem habe ich die Ursache gefunden:

In Datei OpenFileDialog.cs
in Methode SetDialogFlags()
steht u.a. folgendes:

if (!this.DereferenceLinks)
    m_OpenFileName.Flags |= OpenFileNameFlags.NoDereferenceLinks;

this.DereferenceLinks steht standardmäßig auf false.
Wenn man es auf true setzt, klappt das mit den Verlinkungen (zu Dateien/Verzeichnissen), wenn man auf eine *.lnk-Datei klickt.

Hinweis:
this bezieht sich auf die Klasse OpenFileDialog in Datei OpenFileDialog.cs.

Die Eigenschaft DereferenceLinks liest den Wert aus m_bDereferenceLinks.

Dieses ist fest definiert in der Zeile

private bool m_bDereferenceLinks = false;

Beim standardmäßigen OpenFileDialog ist das Flag auf true gesetzt, was im Normalfall sinnvoll ist.
Beim erweiterten OpenFileDialog würde ich das auch standardmäßig auf true setzen.

Generell würde ich die selben Flags setzen, wie standardmäßig auch beim "normalen" Öffnen-Dialog sind. (Ich weiß nicht, ob die anderen Flags diesbezüglich "richtig" definier sind.)

27.12.2009 - 00:19 Uhr

Nun fand ich wieder einen Bug:

Wenn man beim Dialog-Fenster die Größe ändert, dann gibt es unschöne Effekte.

Hier ein Beispiel:

25.12.2009 - 16:29 Uhr

Ich habe noch einen Bug entdeckt, der schon mehrfach zum Programm-Absturz geführt hat (im Test-Client).

Und zwar wenn man schnell den Dialog schließt und erzeut öffnet.
Wenn ich das mehrfach nacheinander mache (öffnen+schließen+öffnen+schließen...) kommt der Fehler.
Im Anhang die Fehlermeldung.
Auch hier weiß ich keinen Grund (kenne mich zu wenig aus), wollte es aber berichten.
Weil es ist ja wünschenswert, daß diese tolle "Erweiterung" stabil läuft und nicht die Programme zum Absturz bringt, die es verwenden.

25.12.2009 - 16:04 Uhr

Eine Kleinigkeit fiel mir noch auf:
Im Bin-Verzeichnis vom TestClient ist die Datei _PostBuildEvent.bat.
Darin steht der Befehl

copy "C:\Program Files\Microsoft\ExtensibleDialogsSource\TestClient\\TestClient.exe.manifest" "C:\Program Files\Microsoft\ExtensibleDialogsSource\TestClient\bin\Debug\"

Auf fremden Computern wird das wohl nicht die gewünschte Wirkung haben.
Vielleicht sollte man besser relative Verzeichnis-Angaben machen (falls das bei Postbuild-Ereignissen klappt).
Außerdem wundert mich, daß bei einem Verzeichnis-Trenner ein doppeltes Backslash verwendet wird.

Hat die bat-Datei vermutlich nichts mit dem vorherigen Problem zu tun, aber ich wollte es mal erwähnen.

25.12.2009 - 15:28 Uhr

Das mit den Verweisen wollte ich jetzt näher untersuchen, aber ich habe Probleme beim Debuggen.
Habe das Projekt runtergeladen, entpackt und in Visual Studio 2008 compiliert+gestartet.

Der Dialog ist als Bibliothek eingebunden (scheint so)
und der TestTemplateFileDialog als Startprojekt.

Wenn ich aus dem VS heraus das "Testprogramm" starte und beim Öffnen-Dialog eine Verlinkung anklicke kommt folgende Meldung:
[Bild jetzt als Anhang] (klicke links unten auf Volle Bildgröße)

Es wird auf ein Verzeichnis verwiesen, das es bei mir nicht gibt und nicht die lokale Datei genommen. So kann ich nicht debuggen. Leider weiß ich nicht, wie ich das Problem behebe. Habe das Projekt neu kompiliert. Keine Ahnung, warum der Debugger nicht die lokale Dateien von CustomizableDialogs nimmt, sondern ganz woanders sucht. (vermutlich das ursprüngliche Verzeichnis vom Author)

Hat jemand eine Idee?

Update:
Ich sah gerade am Datei-Datum, daß die Datei ExtensibleDialogs.dll doch nicht neu erstellt wurde (über F6). Habe das jetzt nochmal nachgeholt durch Rechtsklick auf CustomizableDialogs (in der Projektmappe) und Neu erstellen.
Jetzt kann ich debuggen, aber es kommt dennoch die Fehlermeldung mit einem Verzeichnis des Nutzers "morlho" im Pfad.

18.12.2009 - 16:25 Uhr

Hallo dr4g0n76,

ich bin gerade am Testen Deines tollen Dialoges (TestTemplateFileDialog.exe).
Dabei fällt mir ein Bug auf:

Im Verzeichnis "Eigene Dateien" habe ich Links (*.lnk) auf häufig genutzte Verzeichnisse angelegt.
Beim Doppelklick "springt" der klassische Dialog in das verlinkte Verzeichnis.
Beim erweiterten Dialog schließt sich beim Doppelklick einfach das Fenster.

Gruß Beauty

08.10.2009 - 15:17 Uhr

Danke - die Suchbegriffe waren eine gute Hilfe zur Suche (-:

Anmerkung:
SetWindowRect() gibt es nicht. Sondern statt dessen SetWindowPos().

Wegen "Win32" habe ich ewig gesucht.
Scheinbar ist das auch nichts, was standardmäßig zur Verfügung steht.
In einem Beispiel stand Win32.Api.SetWindowPos(...).
Ein Hinweis, wo das "herkommt" stand nicht dabei.

Für die Verwendung von SetWindowPos(...) aus der User32.dll habe ich ewig gesucht, um herauszufinden, welche Integer-Werte ich für die Flags setzen soll.

Irgendwann fand ich die Klasse Win32 (cs-Datei, GNU-Lizenz), wo u.a. die Flags definiert sind.
http://www.koders.com/csharp/fid181A6A60B7C301EFE9111BA7264496E456F7253D.aspx

Wegen einfacher Verwendbarkeit habe ich eine eigene kleine Klasse geschrieben.
Sie ist für Konsolen-Applikationen
und kann das Konsolen-Fenster verschieben und die Größe ändern.

Vielleicht kann sie ja jemand gebrauchen (-;

Gruß Beauty

Beispiel zur Verwendung:

using SetCommandLineWindowClass;

static void Main(string[] args)
{
    Console.Title = "Konsole in der Ecke";
    Console.WriteLine("Hallo aus der Ecke");
    SetCommandLineWindow.MoveResize(0, 0, 200, 100);
    Console.ReadLine();
}

Hier meine Klasse:

namespace SetCommandLineWindowClass
{
        class SetCommandLineWindow
        {
            // written by Beauty ... [URL]www.beauty-of-darkness.de[/URL]

            [System.Runtime.InteropServices.DllImport("User32.dll")]
            static extern Int32 FindWindow(String lpClassName, String lpWindowName);

            [System.Runtime.InteropServices.DllImport("User32.dll")]
            static extern Boolean SetWindowPos(
                Int32 hWnd,             // window handle
                Int32 hWndInsertAfter,  // placement-order handle
                Int32 X,                // horizontal position
                Int32 Y,                // vertical position
                Int32 cx,               // width
                Int32 cy,               // height
                UInt32 uFlags);         // window positioning flags


            static String windowClass = "ConsoleWindowClass";

            enum WinPosition
            {
                HWND_TOP = 0,
                HWND_BOTTOM = 1,
                HWND_TOPMOST = -1,
                HWND_NOTOPMOST = -2
            }

            enum WinFlags
            {
                SWP_NOSIZE = 0x1,            // Retains current size (ignores the cx and cy parameters)
                SWP_NOMOVE = 0x2,            // Retains current position (ignores the x and y parameters)
                SWP_NOZORDER = 0x4,          // Does not change the owner window's position in the Z-order
                SWP_NOREDRAW = 0x8,
                SWP_NOACTIVATE = 0x10,
                SWP_SHOWWINDOW = 0x40,       // Displays the window
                SWP_HIDEWINDOW = 0x80,       // Hides the window
                SWP_NOSENDCHANGING = 0x400
            }


            public static void Move(Int32 posX, Int32 posY)
            {
                String title = Console.Title;  // backup title
                Console.Title += DateTime.Now.Ticks.ToString();  // make window title unique

                Int32 thisWindow = FindWindow(windowClass, Console.Title);
                SetWindowPos(thisWindow, (Int32)WinPosition.HWND_TOP, posX, posY, 0, 0,
                    (Int32)WinFlags.SWP_SHOWWINDOW | (Int32)WinFlags.SWP_NOSIZE);

                Console.Title = title;  // restore original title
            }


            public static void Resize(Int32 width, Int32 height)
            {
                String title = Console.Title;  // backup title
                Console.Title += DateTime.Now.Ticks.ToString();  // make window title unique

                Int32 thisWindow = FindWindow(windowClass, Console.Title);
                SetWindowPos(thisWindow, (Int32)WinPosition.HWND_TOP, 0, 0, width, height,
                    (Int32)WinFlags.SWP_SHOWWINDOW | (Int32)WinFlags.SWP_NOMOVE);

                Console.Title = title;  // restore original title
            }


            public static void MoveResize(Int32 posX, Int32 posY, Int32 width, Int32 height)
            {
                String title = Console.Title;  // backup title
                Console.Title += DateTime.Now.Ticks.ToString();  // make window title unique

                Int32 thisWindow = FindWindow(windowClass, Console.Title);
                SetWindowPos(thisWindow, (Int32)WinPosition.HWND_TOP, posX, posY, width, height, 
                    (Int32)WinFlags.SWP_SHOWWINDOW);

                Console.Title = title;  // restore original title
            }

        } // SetCommandLineWindow
} // namespace

06.10.2009 - 19:07 Uhr

Hallo,

ich schreibe gerade eine Netzwerk-Bibliothek und nutze zum Testen 2 Konsolenfenster (2 seperate Kommandozeilen-Programme). Die standardmäßige Positionierung ist leider unschön.
(Die Fenster überlappen sich und verschwinden beim Debuggen hinterm VisualStudio-Fenster. Nach jedem Start muß ich die erst "hervorholen" und manuell auf meinen zweiten Monitor verschieben.)

Es wäre schön, wenn sich die Konsolen beim Programmstart per Quellcode-Anweisung an eine bestimmte Stelle auf dem Bildschirm verschieben würden.

Leider fand ich nach einer halben Stunde Suchen+Probieren nicht heraus, wie man das machen kann. (Falsche Suchwörter?)

Hat jemand eine Idee?

Gruß Beauty

22.04.2009 - 15:03 Uhr

Ich hatte auch Probleme damit und mußte ganz schön lange suchen. Deshalb schreibe ich hier ein kleines Code-Beispiel rein. Vielleicht findet man es dann auch besser über eine Suchmaschine.

using System.Collections.Generic;  // needed for this example
        
// use this for the EventHandler of a button
private void button1_Click(object sender, EventArgs e)
{
    ColorDialog colDialog = new ColorDialog();
    colDialog.FullOpen = true;

    // define colours
    Color[] colourList = { 
        Color.Red,   // by name
        Color.Green, 
        Color.Blue,
        Color.FromArgb(255, 255, 0),        // RGB (yellow)
        Color.FromArgb(127, 255, 255, 0),   // Alpha + RGB (yellow)
        ColorTranslator.FromHtml("#ff0000") // HTML (red)
    };

    // convert to other format
    List<Int32> customColours = new List<Int32>();
    foreach (Color col in colourList)
        customColours.Add(ColorTranslator.ToOle(col));

    // insert + show dialog
    colDialog.CustomColors = customColours.ToArray();
    colDialog.ShowDialog();

}

oh, ich habe gerade gemerkt, daß ich die Kommentare auf englisch geschrieben habe (Gewohnheit). Aber dennoch sollte es verständlich sein (-;

Schlagwort: ToArgb()