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);
}
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.
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?
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
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. 🙂
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.)
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.
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.
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.
Ü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