Hi All i got a problem with dataview that get data from datatabel (Col1 : ID,Col2: Time)
and I'm sorting by Time in desc ... when the values for example {40.21,80.21,70.25,25.2} the dataview sorting them as I need but when one of values goes above 100 for example {40.21,80.21,100.25,25.2} the dataview always sort the highest number is the buttom, I don't know why .. This is a sample code
Dim dt As New DataTable
dt.Columns.Add("ID")
dt.Columns.Add("Time")
dt.Rows.Add(New String() {"1", "90.24"})
dt.Rows.Add(New String() {"2", "80.25"})
dt.Rows.Add(New String() {"3", "70.22"})
dt.Rows.Add(New String() {"4", "102.12"})
Dim dv As New DataView(dt)
dv.Sort = "Time Desc"
Thanks in advance ...
You are sorting a String, so what have you expected? "10000" is lower than "2" because "1" is alphabetically lower than "2" just as "abbbb" would be lower than "b".
You need to use the correct data-type(in this case i assume Double) to get the correct(numeric) sorting:
Dim dt As New DataTable
dt.Columns.Add("ID", GetType(Int32))
dt.Columns.Add("Time", GetType(Double))
dt.Rows.Add(1, 90.24)
dt.Rows.Add(2, 80.25)
dt.Rows.Add(3, 70.22)
dt.Rows.Add(4, 102.12)
Dim dv As New DataView(dt)
dv.Sort = "Time Desc"
Result:
4 102,12
1 90,24
2 80,25
3 70,22
Like Tim says, you are sorting by a string. I had to deal with a lot of mixed numbers and strings in multiple columns so I wrote a class to do the sorting (below). It properly sorts numbers as numbers, dates as dates and mixed number/string fields as users would expect.
I had columns with data like
"Day 1 Timepoint 1"
"Day 14 Timepoint 3"
"Day 15 Timepoint 10"
... And mixed numbers and dates.
The class takes a data table and a list of columns to include in the sort. Most important column first in the list, add as many columns as you want to the sort.
using System;
using System.Data;
using System.Linq;
public class DataTableSorter
{
public enum SortDirection
{
Ascending,
Descending
}
private const string MC_TEMP_COL_NAME = "SorterXXXColumn";
private const int MC_NUM_PAD_COLS = 12;
private static string msPAD = new string('0', MC_NUM_PAD_COLS);
public static DataTable SortTable(DataTable oDT, SortDirection eSortDir, params string[] asColumns)
{
//so DataView has limited sorting capability, this builds it out so numbers and strings work out well.
oDT.Columns.Add(new DataColumn(MC_TEMP_COL_NAME, typeof(string)));
foreach (DataRow oDR in oDT.Rows)
{
string sSortable = string.Empty;
foreach(string sCol in asColumns)
sSortable += Sortable(oDR[sCol]);
oDR[MC_TEMP_COL_NAME] = sSortable;
}
//Using DataView for sorting DataTable's data
using (DataView oSortedView = oDT.DefaultView)
{
oSortedView.Sort = string.Format("[{0}] {1}", MC_TEMP_COL_NAME, eSortDir == SortDirection.Ascending ? "ASC" : "DESC");
using (DataTable oDTreturn = oSortedView.ToTable())
{
//remove special sort column
oDTreturn.Columns.RemoveAt(oDTreturn.Columns.Count - 1);
return oDTreturn;
}
}
}
private static string Sortable(object oValue)
{
DateTime oDtT;
if (string.IsNullOrWhiteSpace(oValue.ToString()))
{
return string.Empty;
}
else if (DateTime.TryParse(oValue.ToString(), out oDtT))
{
System.Diagnostics.Debug.Print(oValue.ToString() + "\t" + String.Format("{0:yyyyMMddHHmmss.FFFF}", oDtT));
return string.Format("{0:yyyyMMddHHmmss.FFFF}", oDtT);
}
else
{
//pad out all numbers with lots of zeros, so that numbers sort as numbers.
char[] acVal = oValue.ToString().ToCharArray();
string sBuff = string.Empty;
string sRC = string.Empty;
bool bAfterDecmal = false;
int iCharCount = acVal.Length;
for (int i = 0; i < iCharCount; i++)
{
char c = acVal[i];
bool bIsNumeric = "0123456789".Contains(c);
bool bEndSection = false;
if (i == (iCharCount - 1))
{
bEndSection = true;
}
else
{
char cNext = acVal[i + 1];
if (bIsNumeric != "0123456789".Contains(cNext))
{
bEndSection = true;
}
else if (c == '.')
{
bEndSection = true;
bIsNumeric = false;
}
else if (cNext == '.')
{
bEndSection = true;
}
}
sBuff += c;
if (bEndSection)
{
if (bIsNumeric)
{
if (bAfterDecmal)
{
// FOR DECMALS, JUST RIGHT-PAD TO MC_NUM_PAD_COLS ZEROS:
sRC += (sBuff + msPAD).Substring(0, MC_NUM_PAD_COLS);
bAfterDecmal = true;
}
else
{
// for integers, left pad to MC_NUM_PAD_COLS zeros.
sRC += (msPAD + sBuff).Substring(sBuff.Length);
}
}
else
{
// upper case all strings, for better ordering.
sRC += sBuff.ToUpper();
}
sBuff = string.Empty;
} // CHANGE IN NUMERIC STATUS
if (c == '.')
bAfterDecmal = true;
}
System.Diagnostics.Debug.Print(oValue.ToString() + "\t" + sRC);
return sRC;
}
}
}
dt.Rows.Add(New String() {"1", "90.24"})
change it to
dt.Rows.Add(New Integer() {"1", "90.24"})
Related
Ok so I have been making a simple code editor in vb.net for go.. (for personal uses)
I tried this code -
Dim tokens As String = "(break|default|func|interface|select|case|defer|go|map|struct|chan|else|goto|package|switch|const|fallthrough|if|range|type|continue|for|import|return|var)"
Dim rex As New Regex(tokens)
Dim mc As MatchCollection = rex.Matches(TextBox2.Text)
Dim StartCursorPosition As Integer = TextBox2.SelectionStart
For Each m As Match In mc
Dim startIndex As Integer = m.Index
Dim StopIndex As Integer = m.Length
TextBox2.[Select](startIndex, StopIndex)
TextBox2.SelectionColor = Color.FromArgb(0, 122, 204)
TextBox2.SelectionStart = StartCursorPosition
TextBox2.SelectionColor = Color.RebeccaPurple
Next
but I couldn't add something like print statements say I want a fmt.Println("Hello World"), that is not possible, anyone help me?
I want a simple result that will do proper syntax without glitching text colors like this current code does.
Here's a code showing how to update highlighting with strings and numbers.
You would need to tweak it further to support syntax like comments, etc.
private Regex BuildExpression()
{
string[] exprs = {
"(break|default|func|interface|select|case|defer|go|map|struct|chan|else|goto|package|switch|const|fallthrough|if|range|type|continue|for|import|return|var)",
#"([0-9]+\.[0-9]*(e|E)(\+|\-)?[0-9]+)|([0-9]+\.[0-9]*)|([0-9]+)",
"(\"\")|\"((((\\\\\")|(\"\")|[^\"])*\")|(((\\\\\")|(\"\")|[^\"])*))"
};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < exprs.Length; i++)
{
string expr = exprs[i];
if ((expr != null) && (expr != string.Empty))
sb.Append(string.Format("(?<{0}>{1})", "_" + i.ToString(), expr) + "|");
}
if (sb.Length > 0)
sb.Remove(sb.Length - 1, 1);
RegexOptions options = RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase;
return new Regex(sb.ToString(), options);
}
private void HighlightSyntax()
{
var colors = new Dictionary<int, Color>();
var expression = BuildExpression();
Color[] clrs = { Color.Teal, Color.Red, Color.Blue };
int[] intarray = expression.GetGroupNumbers();
foreach (int i in intarray)
{
var name = expression.GroupNameFromNumber(i);
if ((name != null) && (name.Length > 0) && (name[0] == '_'))
{
var idx = int.Parse(name.Substring(1));
if (idx < clrs.Length)
colors.Add(i, clrs[idx]);
}
}
foreach (Match match in expression.Matches(richTextBox1.Text))
{
int index = match.Index;
int length = match.Length;
richTextBox1.Select(index, length);
for (int i = 0; i < match.Groups.Count; i++)
{
if (match.Groups[i].Success)
{
if (colors.ContainsKey(i))
{
richTextBox1.SelectionColor = colors[i];
break;
}
}
}
}
}
What we found during development of our Code Editor libraries, is that the regular expression-based parsers are hard to adapt to fully support advanced syntax like contextual keywords (LINQ) or interpolated strings.
You might find a bit more information here:
https://www.alternetsoft.com/blog/code-parsing-explained
The most accurate syntax highlighting for VB.NET can be implemented using Microsoft.CodeAnalysis API, it's the same API used internally by Visual Studio text editor.
Below is sample code showing how to get classified spans for VB.NET code (every span contains start/end position within the text and classification type, i.e. keyword, string, etc.). These spans then can be used to highlight text inside a textbox.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
public class VBClassifier
{
private Workspace workspace;
private static string FileContent = #"
Public Sub Run()
Dim test as TestClass = new TestClass()
End Sub";
public void Classify()
{
var project = InitProject();
var doc = AddDocument(project, "file1.vb", FileContent);
var spans = Classify(doc);
}
protected IEnumerable<ClassifiedSpan> Classify(Document document)
{
var text = document.GetTextAsync().Result;
var span = new TextSpan(0, text.Length);
return Classifier.GetClassifiedSpansAsync(document, span).Result;
}
protected Document AddDocument(Project project, string fileName, string code)
{
var documentId = DocumentId.CreateNewId(project.Id, fileName);
ApplySolutionChanges(s => s.AddDocument(documentId, fileName, code, filePath: fileName));
return workspace.CurrentSolution.GetDocument(documentId);
}
protected virtual void ApplySolutionChanges(Func<Solution, Solution> action)
{
var solution = workspace.CurrentSolution;
solution = action(solution);
workspace.TryApplyChanges(solution);
}
protected MefHostServices GetRoslynCompositionHost()
{
IEnumerable<Assembly> assemblies = MefHostServices.DefaultAssemblies;
var compositionHost = MefHostServices.Create(assemblies);
return compositionHost;
}
protected Project CreateDefaultProject()
{
var solution = workspace.CurrentSolution;
var projectId = ProjectId.CreateNewId();
var projectName = "VBTest";
ProjectInfo projectInfo = ProjectInfo.Create(
projectId,
VersionStamp.Default,
projectName,
projectName,
LanguageNames.VisualBasic,
filePath: null);
ApplySolutionChanges(s => s.AddProject(projectInfo));
return workspace.CurrentSolution.Projects.FirstOrDefault();
}
protected Project InitProject()
{
var host = GetRoslynCompositionHost();
workspace = new AdhocWorkspace(host);
return CreateDefaultProject();
}
}
Update:
Here's a Visual Studio project demonstrating both approaches:
https://drive.google.com/file/d/1LLuzy7yDFAE-v40I7EswECYQSthxheEf/view?usp=sharing
How do I get two input values compared to my query records?
For example, I enter 500 Double, and I want everyone who has over 500 Double on my list.
if I enter 300 Doubles and 150 Triples. Only display everybody who has more than 300 Doubles and more than 150 Triples. Right now, displays the doubles that are more than the input value.
namespace SQLiteIntegration
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (HasValidInput())
{
int doubles = int.Parse(DoublesTextBox.Text);
int triples = int.Parse(TriplesTextBox.Text);
//MARKER - Probably an error here
DataTable dt = new DataTable();
string datasource = #"Data Source=../../lahman2016.sqlite;";
//Batting.'2B' is the number of doubles a player hit in a season
//Batting.'3B' is the number of triples a player hit in a season
string sql = $"SELECT namefirst, namelast, sum(Batting.'2B'), sum(Batting.'3B') from Master JOIN Batting on Master.playerID = Batting.playerID GROUP BY Master.playerid HAVING SUM(Batting.'2B') AND SUM(Batting.'3B') > {doubles};";
using (SQLiteConnection conn = new SQLiteConnection(datasource))
{
conn.Open();
SQLiteDataAdapter da = new SQLiteDataAdapter(sql, conn);
da.Fill(dt);
conn.Close();
}
playerList.Clear();
foreach (DataRow row in dt.Rows)
{
// MARKER: Making something different show up
string playerRow = $"{row[0].ToString()} {row[1].ToString()} - 2B = {row[2].ToString()}, 3B = {row[3].ToString()}";
playerList.Add(playerRow);
}
populateList();
}
}
private List<string> playerList = new List<string>();
private void populateList()
{
ListView.Items.Clear();
foreach (string s in playerList)
{
ListView.Items.Add(s);
}
}
private string ValidateTextBox(TextBox box, string name)
{
string message = "";
string text = box.Text;
int amount = 0;
if (text == "")
box.Text = "0";
else
{
bool isNumber = int.TryParse(text, out amount);
if (!isNumber)
{
message += $"Invalid Input - {name} is not a number! ";
}
if (amount < 0)
{
message += $"Invalid Input - {name} is negative! ";
}
}
return message;
}
private bool HasValidInput()
{
string message = ValidateTextBox(DoublesTextBox, "Doubles") +
ValidateTextBox(TriplesTextBox, "Triples");
if (message == "")
{
return true;
}
else
{
MessageBox.Show(message);
return false;
}
}
}
}
I am expecting if I enter 300 Doubles and 150 Triples. Only display everybody who has more than 300 Doubles and more than 150 Triples. Right now, displays the doubles that are more than the input value.
I wrote a function that will return a single sql record as a dictionary. Is it possible to return an array of dictionaries so I can return multiple records in this way?
public static async Task<Dictionary<string, string>> SQLMultiRecordToDictionary(string TableName, string SearchField, string SearchValue)
{
Dictionary<string, string> QueryResult = new Dictionary<string, string>();
// is TableName sane
if (!IsTextSane(TableName)) { return QueryResult; }
//
await using (var connection = new SqliteConnection("Data Source=" + dbFullPathName))
{
connection.Open();
SqliteCommand sqlcmd = connection.CreateCommand();
sqlcmd.CommandText = "SELECT * FROM " + TableName + " WHERE " + SearchField + "=#SearchValue";
sqlcmd.Parameters.AddWithValue("#SearchValue", SearchValue);
SqliteDataReader sqlreader = sqlcmd.ExecuteReader();
// generate dictionary keys with blank values
// this prevents key not existing issues when no record is returned
// i prefer no/blank values in the keys when no record returned for this project
for (int i = 0; i < sqlreader.FieldCount; i++)
{
QueryResult.Add(sqlreader.GetName(i), ""); // blank value
}
// add the values to the keys
while (sqlreader.Read())
{
for (int i = 0; i <= sqlreader.FieldCount - 1; i++)
{
QueryResult[sqlreader.GetName(i)] = sqlreader.GetString(i);
}
}
return QueryResult;
}
}
The working end result thanks to Tisa:
public static async Task<List<Dictionary<string, string>>> SQLMultiRecordToDictionaryList(string TableName, string SearchField, string SearchValue)
{
List<Dictionary<string, string>> QueryResult = new List<Dictionary<string, string>>();
Dictionary<string, string> SQLRecord = new Dictionary<string, string>();
//
// is TableName sane, if not return nothing
if (!IsTextSane(TableName)) { return QueryResult; }
//
await using (var connection = new SqliteConnection("Data Source=" + dbFullPathName))
{
connection.Open();
SqliteCommand sqlcmd = connection.CreateCommand();
sqlcmd.CommandText = "SELECT * FROM " + TableName + " WHERE " + SearchField + "=#SearchValue";
sqlcmd.Parameters.AddWithValue("#SearchValue", SearchValue);
SqliteDataReader sqlreader = sqlcmd.ExecuteReader();
// generate dictionary keys with blank values if no rows
// this prevents key not existing issues when no record is returned
// i prefer no/blank values in the keys when no record returned for this project
if (!sqlreader.HasRows)
{
for (int i = 0; i < sqlreader.FieldCount; i++)
{
SQLRecord.Add(sqlreader.GetName(i), ""); // blank value
}
QueryResult.Add(SQLRecord);
}
//
// add the values to the keys if there are rows (this doesn't run if no rows returned)
while (sqlreader.Read())
{
SQLRecord = new Dictionary<string, string>();
for (int i = 0; i <= sqlreader.FieldCount - 1; i++)
{
SQLRecord.Add(sqlreader.GetName(i), sqlreader.GetString(i));
}
QueryResult.Add(SQLRecord);
}
return QueryResult;
}
}
I want to use NameValueCollection in windows phone 8, but I can not see this option in WP8 SDK. Can you help me please?
This function has been removed.
But a query can be manipulated using parsing and a SortedDictionary. i.e. This snippet sorts a query string:
public string sortQuery(string myUrl)
{
string url = myUrl.Substring(0, myUrl.IndexOf("?") + 1);
string q = myUrl.Substring(myUrl.IndexOf("?") + 1);
string[] pr = q.Split('&');
SortedDictionary<string,string> d = new SortedDictionary<string,string>();
foreach (string s in pr)
{
string[] prm = s.Split('=');
string key = prm[0];
string value = "";
if (prm.Length > 1) { value = "=" + prm[1]; }
d.Add(key, value);
}
string result = "";
foreach (var k in d.Keys)
{
result += k + d[k] + "&";
}
result = result.Substring(0, result.Length - 1);
return url + result;
}
I'm using the EPPlus .NET library in order to export data from SQL Server to an Excel file.
I'm using the SqlConnection class to read the data. For every row of the SqlDataReader cursor, I iterate through all the excel cells for the corresponding row, and enter the data from the reader.
The issue is that I'm getting an "out of memory" error when im using this function for large tables. I need a method to create some kind of a buffer inside the Read CURSOR.
A concise code example:
Dim sqlConnection As SqlConnection = New SqlConnection()
sqlConnection.ConnectionString = sqlConnectionString.ConnectionString 'connectionstring built before
Dim query As SqlCommand = New SqlCommand(query...)
Dim newFileStream As New FileStream("c:\junk\test.xlsx", System.IO.FileMode.Create,System.IO.FileAccess.ReadWrite)
Using excelApp As New ExcelPackage(newFileStream)
sqlConnection.Open()
Dim sqlReader As SqlDataReader = query.ExecuteReader()
Dim numOfColumns As Byte = sqlReader.FieldCount()
Dim rowNumber As Integer = 1
While sqlReader.Read()
Dim currentColumn As Byte
For currentColumn = 1 To numOfColumns
ws.Cells(rowNumber,currentColumn).Value = sqlReader.Item(currentColumn - 1)
Next
rowNumber += 1
End While
excelApp.Save()
End Using
newFileStream.Close()
Since you will have to split the files anyway when you hit Excel's limits, here's some code that reads from the database in chunks into multiple Excel files:
static class Program
{
private static string _dataSource;
private static string _database;
private static string _table;
private static string _outputPath;
private static int _batchSize;
public static void Main()
{
try
{
_dataSource = ConfigurationManager.AppSettings["DataSource"];
_database = ConfigurationManager.AppSettings["Database"];
_table = ConfigurationManager.AppSettings["Table"];
_outputPath = ConfigurationManager.AppSettings["OutputPath"];
_batchSize = int.Parse(ConfigurationManager.AppSettings["BatchSize"]);
CreateExcel(_dataSource, _database, _table, _outputPath, "SELECT * FROM " + _table);
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine("All done!");
}
public static void CreateExcel(string dataSource, string databaseName, string tableName, string outputFilePath, string queryNoParameters)
{
var sqlConnectionString = new SqlConnectionStringBuilder
{
DataSource = dataSource,
InitialCatalog = databaseName,
IntegratedSecurity = true
};
using (var connection = new SqlConnection(sqlConnectionString.ConnectionString))
{
connection.Open();
using (var command = new SqlCommand { Connection = connection, CommandType = CommandType.Text, CommandText = queryNoParameters })
using (var sqlReader = command.ExecuteReader())
{
int i = 0;
while (WriteExcelFile(tableName, GetFileInfo(databaseName, tableName, outputFilePath, i++),
sqlReader, sqlReader.FieldCount, _batchSize))
{
Console.WriteLine("Reading next batch...");
}
}
}
}
private static bool WriteExcelFile(string tableName, FileInfo fileInfo, IDataReader sqlReader, int numOfColumns, int count)
{
using (var excelPackage = new ExcelPackage(fileInfo))
{
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add(tableName);
Console.WriteLine("Populating header row...");
for (var currentColumn = 1; currentColumn <= numOfColumns; currentColumn++)
{
worksheet.Cells[1, currentColumn].Value = sqlReader.GetName(currentColumn - 1);
worksheet.Column(currentColumn).Style.Numberformat.Format =
TranslateSystemtypeToExceltype(sqlReader.GetFieldType(currentColumn - 1));
}
Console.WriteLine("Reading data rows...");
int rowNumber = 2;
while (rowNumber <= count + 1 && sqlReader.Read())
{
for (var currentColumn = 1; currentColumn <= numOfColumns; currentColumn++)
worksheet.Cells[rowNumber, currentColumn].Value = sqlReader[currentColumn - 1];
rowNumber++;
}
if (rowNumber == 2) //nothing read
{
Console.WriteLine("Nothing to read, reached end of table!");
return false;
}
Console.WriteLine("Saving Excel file...");
excelPackage.Save();
return rowNumber == count + 2; //in which case we want to read more
}
}
private static FileInfo GetFileInfo(string databaseName, string tableName, string outputFilePath, int i)
{
return new FileInfo(Path.Combine(outputFilePath,
Path.ChangeExtension(
string.Format("{0}_{1}_{2}", databaseName, tableName.Replace('.', '-'), i), "xlsx")));
}
public static string TranslateSystemtypeToExceltype(Type sysType)
{
if (sysType == typeof(string))
return "#";
if (sysType == typeof(DateTime))
return "dd/MM/YYYY";
if (sysType == typeof(Decimal))
return "0.000";
if (sysType == typeof(bool))
return "#";
if (sysType == typeof(int))
return "0";
if (sysType == typeof(short))
return "0";
if (sysType == typeof(double))
return "0.000";
return "General";
}
}