Is DataGridView wrong choice? - c#

I am new to C# and Windows Forms so please be patient. I am making a Windows Form that lets you load a video, load a script, then makes captions. I want to display a table where the data will be populated automatically as they mark starts and ends of caption and select text and will be editable. At the end I want to save all the data to an xml file. A DataGridView UI-wise seems like exactly what I want, but I can't figure out backend how to get the data out of the DataGridView ( preferably in a dataset).
I am now considering using a ListView with multiple columns instead. Any advice would be greatly appreciated

Datagridview should work just fine for that application and you can easily retrieve any data you save to it by doing:
dgvThing.DataSource;
That will contain whatever type that you have saved into the Datagridview (List, array, etc).
Example:
public class SuperFunObject {
public TimeSpan start { get; set; }
public TimeSpan end { get; set; }
public string selectedText { get; set; }
public SuperFunObject(Timespan a, Timespan b, string text) {
start = a;
end = b;
selectedText = text;
}
}
List<SuperFunObject> funList = new List<SuperFunObject>();
funList.Add(new SuperFunObject(TimeSpan.FromSeconds(0.0),TimeSpan.FromSeconds(20.0),"Hello"));
dgvThing.DataSource = funList;
...
...
//retrive your list
List<SuperFunObject> getData = ((List<SuperFunObject>)dgvThing.DataSource);
I hope the example helps a bit. Side note, the reason for the accessors (get,set) are for the Datagridview to be able to retrieve the data from the object for display.

Here is a little ditty that'll save a class that you populate into an array from your datasource to am XML file path that you specify in the parameter.
public static bool SaveXMLObjectToFile(object IncomingXMLObject, string Path)
{
string xmlString = null;
File TheFileIn = default(File);
string docname = null;
StreamWriter WriteAFile = default(StreamWriter);
string filelocation = null;
//Dim filelocation As String
System.IO.MemoryStream MemStream = new System.IO.MemoryStream();
System.Xml.Serialization.XmlSerializer Ser = default(System.Xml.Serialization.XmlSerializer);
System.Text.Encoding encodingvalue = System.Text.UTF8Encoding.UTF8;
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(MemStream, encodingvalue);
bool Result = false;
try {
File.Delete(Path);
Ser = new System.Xml.Serialization.XmlSerializer(IncomingXMLObject.GetType);
Ser.Serialize(writer, IncomingXMLObject);
MemStream = writer.BaseStream;
//as system.io.memorystream
xmlString = UTF8ByteArrayToString(MemStream.ToArray());
//Will Not Convert Byte Array from Diagram
filelocation = Path;
WriteAFile = TheFileIn.AppendText(filelocation);
WriteAFile.Write(xmlString);
WriteAFile.Close();
Result = true;
} catch (Exception e) {
Result = false;
}
return Result;
}

Related

Print NFC tag data in a listview on xamarin Forms

So I have a project with my group we are trying to print data info from a NFC tag, we have done the part of reading the data but can't seem to find a way of printing it once read to a listview on another class that will receive all the data.
*We reused some NFC code.
string cedula = data.Replace("en", string.Empty);
string estudiante = data2.Replace("en", string.Empty);
public static string ByteArrayToString(byte[] ba)
{
var shb = new SoapHexBinary(ba);
return shb.ToString();
}
JObject o = new JObject();
public void GuardarDatosJson(String nombre, String cedula)
{
JArray array = new JArray();
array.Add(nombre);
array.Add(DateTime.Now.ToString());
o[cedula + DateTime.Now.Ticks] = array;
EstudianteData.listado = o.ToString();
}
}
}

Reading the file only once for every method call

I am new to object-oriented programming and I am working on a small personal project with some SQL scripts.
I have a scenario where a SQL script calls a static method with a file path as input.
queries = Select Query from Table where Utils.ContainsKeyword(Query, #Path1) AND NOT Utils.ContainsKeyword(Query, #Path2);
I had initially created a static class that does the following:
public static class Utils
{
public static bool ContainsKeyword(string query, string path)
{
var isQueryInFile = false;
var stringFromFile = GetStringFromFile(path);
List<Regex>regexList = GetRegexList(stringFromFile);
if(regexList!= null)
{
isQueryInFile = regexList.Any(pattern => pattern.IsMatch(query));
}
return isQueryInFile;
}
private static string GetStringFromFile(string path)
{
var words = String.Empty;
if(!string.IsNullOrEmpty(path))
{
try
{
using (StreamReader sr = File.OpenText(path))
{
words = sr.ReadToEnd().Replace(Environment.Newline, "");
}
}
catch { return words; }
}
return words;
}
private static List<Regex> GetRegexList(string words)
{
if(string.IsNullOrEmpty(words)) { return null; }
return words.Split(',').Select(w=> new Regex(#"\b" + Regex.Escape(w) + #'\b', RegexOptions.Compiled | RegexOptions.IgnoreCase)).ToList();
}
}
My problem is that I neither want to read from the file every time the ContainsKeyword static method is called nor do I want to create a new RegexList every time. Also, I cannot change the SQL script and I have to send the path to the file as an input parameter for the method call in the SQL script since the path might change in the future.
Is there a way to make sure I only read the contents from the input path only once, store them in a string, and use the string for the match with different input queries?
To read the content only once, saving in memory will probaby be needed. Memory capacity could be an issue.
public Dictionary<string, string> FileContentCache { get; set; } // make sure that gets initialized
public string GetFileContentCache(string path)
{
if (FileContentCache == null) FileContentCache = new Dictionary<string, string>();
if (FileContentCache.ContainsKey(path))
return FileContentCache[path];
var fileData = GetStringFromFile(path);
FileContentCache.Add(path, fileData);
return fileData;
}

Determine if a Database is "Equal" to a DacPackage

Is there a way to use the SQL Server 2012 Microsoft.SqlServer.Dac Namespace to determine if a database has an identical schema to that described by a DacPackage object? I've looked at the API docs for DacPackage as well as DacServices, but not having any luck; am I missing something?
Yes there is, I have been using the following technique since 2012 without issue.
Calculate a fingerprint of the dacpac.
Store that fingerprint in the target database.
The .dacpac is just a zip file containing goodies like metadata, and
model information.
Here's a screen-grab of what you will find in the .dacpac:
The file model.xml has XML structured like the following
<DataSchemaModel>
<Header>
... developer specific stuff is in here
</Header>
<Model>
.. database model definition is in here
</Model>
</<DataSchemaModel>
What we need to do is extract the contents from <Model>...</Model>
and treat this as the fingerprint of the schema.
"But wait!" you say. "Origin.xml has the following nodes:"
<Checksums>
<Checksum Uri="/model.xml">EB1B87793DB57B3BB5D4D9826D5566B42FA956EDF711BB96F713D06BA3D309DE</Checksum>
</Checksums>
In my experience, this <Checksum> node changes regardless of a schema change in the model.
So let's get to it.
Calculate the fingerprint of the dacpac.
using System.IO;
using System.IO.Packaging;
using System.Security.Cryptography;
static string DacPacFingerprint(byte[] dacPacBytes)
{
using (var ms = new MemoryStream(dacPacBytes))
using (var package = ZipPackage.Open(ms))
{
var modelFile = package.GetPart(new Uri("/model.xml", UriKind.Relative));
using (var streamReader = new System.IO.StreamReader(modelFile.GetStream()))
{
var xmlDoc = new XmlDocument() { InnerXml = streamReader.ReadToEnd() };
foreach (XmlNode childNode in xmlDoc.DocumentElement.ChildNodes)
{
if (childNode.Name == "Header")
{
// skip the Header node as described
xmlDoc.DocumentElement.RemoveChild(childNode);
break;
}
}
using (var crypto = new SHA512CryptoServiceProvider())
{
byte[] retVal = crypto.ComputeHash(Encoding.UTF8.GetBytes(xmlDoc.InnerXml));
return BitConverter.ToString(retVal).Replace("-", "");// hex string
}
}
}
}
With this fingerprint now available, pseudo code for applying a dacpac can be:
void main()
{
var dacpacBytes = File.ReadAllBytes("<path-to-dacpac>");
var dacpacFingerPrint = DacPacFingerprint(dacpacBytes);// see above
var databaseFingerPrint = Database.GetFingerprint();//however you choose to do this
if(databaseFingerPrint != dacpacFingerPrint)
{
DeployDacpac(...);//however you choose to do this
Database.SetFingerprint(dacpacFingerPrint);//however you choose to do this
}
}
Here's what I've come up with, but I'm not really crazy about it. If anyone can point out any bugs, edge cases, or better approaches, I'd be much obliged.
...
DacServices dacSvc = new DacServices(connectionString);
string deployScript = dacSvc.GenerateDeployScript(myDacpac, #"aDb", deployOptions);
if (DatabaseEqualsDacPackage(deployScript))
{
Console.WriteLine("The database and the DacPackage are equal");
}
...
bool DatabaseEqualsDacPackage(string deployScript)
{
string equalStr = string.Format("GO{0}USE [$(DatabaseName)];{0}{0}{0}GO{0}PRINT N'Update complete.'{0}GO", Environment.NewLine);
return deployScript.Contains(equalStr);
}
...
What I really don't like about this approach is that it's entirely dependent upon the format of the generated deployment script, and therefore extremely brittle. Questions, comments and suggestions very welcome.
#Aaron Hudon answer does not account for post script changes. Sometimes you just add a new entry to a type table without changing the model. In our case we want this to count as new dacpac. Here is my modification of his code to account for that
private static string DacPacFingerprint(string path)
{
using (var stream = File.OpenRead(path))
using (var package = Package.Open(stream))
{
var extractors = new IDacPacDataExtractor [] {new ModelExtractor(), new PostScriptExtractor()};
string content = string.Join("_", extractors.Select(e =>
{
var modelFile = package.GetPart(new Uri($"/{e.Filename}", UriKind.Relative));
using (var streamReader = new StreamReader(modelFile.GetStream()))
{
return e.ExtractData(streamReader);
}
}));
using (var crypto = new MD5CryptoServiceProvider())
{
byte[] retVal = crypto.ComputeHash(Encoding.UTF8.GetBytes(content));
return BitConverter.ToString(retVal).Replace("-", "");// hex string
}
}
}
private class ModelExtractor : IDacPacDataExtractor
{
public string Filename { get; } = "model.xml";
public string ExtractData(StreamReader streamReader)
{
var xmlDoc = new XmlDocument() { InnerXml = streamReader.ReadToEnd() };
foreach (XmlNode childNode in xmlDoc.DocumentElement.ChildNodes)
{
if (childNode.Name == "Header")
{
// skip the Header node as described
xmlDoc.DocumentElement.RemoveChild(childNode);
break;
}
}
return xmlDoc.InnerXml;
}
}
private class PostScriptExtractor : IDacPacDataExtractor
{
public string Filename { get; } = "postdeploy.sql";
public string ExtractData(StreamReader stream)
{
return stream.ReadToEnd();
}
}
private interface IDacPacDataExtractor
{
string Filename { get; }
string ExtractData(StreamReader stream);
}

AppendAllText producing invalid JSON

I have a JSON file containing:
[{
"title":"Colors",
"text":"1. White 2. Blue 3. Red 4. Yellow 5. Green"
}]
If I use
string json = JsonConvert.SerializeObject(favecolors, Formatting.Indented);
var jsonFile= Server.MapPath("~/App_Data/favecolors.json");
System.IO.File.AppendAllText(#jsonFile, ","+json);
I can append a JSON object to the file resulting in:
[{
"title":"Colors",
"text":"1. White 2. Blue 3. Red 4. Yellow 5. Green"
}],{
"title":"Colors",
"text":"1. White 2. Blue 3. Red 4. Yellow 5. Green"
}
which isn't valid JSON because the right square bracket is in the wrong place. Can anybody help?
If the format of the json of your file is going to be always the same, in that case a json array with at least one node [{},{}] you could do that
var jsonFile = Server.MapPath("~/App_Data/favecolors.json");
FileStream fs = new FileStream(#jsonFile, FileMode.Open, FileAccess.ReadWrite);
fs.SetLength(fs.Length - 1); // Remove the last symbol ']'
fs.Close();
string json = JsonConvert.SerializeObject(favecolors, Formatting.Indented);
System.IO.File.AppendAllText(#jsonFile, "," + json + "]");
It is not the most elegant solution but it should make that you want to do.
Note: this solution is very tricky, be sure that the content of your file ends with the ']' symbol, otherwise you would rather do the following: 1) Read the file into a var, 2) concat the new json (fitting it properly), 3) write the file with the merged json.
You could try something more generic, instead of adding/removing the ending bracket. Hope the following example fits your needs.
[JsonObject]
public class FavoriteColor
{
public FavoriteColor()
{}
public FavoriteColor(string title, string text)
{
Title = title;
Text = text;
}
[JsonProperty(PropertyName = "title")]
public string Title { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Append new objects to your file
private async Task Append()
{
// Read file content and deserialize
string content = await ReadAsync("json.txt");
var colors = new List<FavoriteColor>();
if (!string.IsNullOrWhiteSpace(content))
colors.AddRange(JsonConvert.DeserializeObject<List<FavoriteColor>>(content));
// Add your new favorite color!
var fav = new FavoriteColor("new", "new color");
colors.Add(fav);
// Writo back to file
await WriteAsync("json.txt", JsonConvert.SerializeObject(colors));
}
// Async read
private async Task<string> ReadAsync(string file)
{
if (!File.Exists(file))
return null;
string content;
using (var fileStream = File.OpenRead(file))
{
byte[] buffer = new byte[fileStream.Length];
await fileStream.ReadAsync(buffer, 0, (int)fileStream.Length);
content = Encoding.UTF8.GetString(buffer);
}
return content;
}
// Async write
private async Task WriteAsync(string file, string content)
{
using (var fileStream = File.OpenWrite(file))
{
byte[] buffer = (new UTF8Encoding()).GetBytes(content);
await fileStream.WriteAsync(buffer, 0, buffer.Length);
}
}
}

HTTPHandler write Binary Data to Response , load image

iv'e got a repeater bonded to a list of entities
BL_Engine engine = (BL_Engine)Application["engine"];
List<AppProduct> products = engine.Get_Products();
Repeater1.DataSource = products;
Repeater1.DataBind();
iv'e also got a user control i use to represent these product entities , i do this by overriding the Databind() in the user control :
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
lbl_title.Text = product.Title;
lbl_short.Text = product.Short;
lbl_date.Text = product.Date.ToShortDateString();
Session["current_img"] = product.Image1;
base.DataBind();
}
in my HttpHanlder object kept in a .ashx file i write the image to the response
the response happens only once so only the last picture is written to (ALL) the user controls.
public void ProcessRequest(HttpContext context)
{
byte [] image = (byte[])context.Session["current_img"];
context.Response.ContentType = "image/bmp";
context.Response.OutputStream.Write(image, 0, image.Length);
}
any idea how i could write the binary data for each individual control
thanks in advance
eran.
Let me suggest a different approach.
Declare a regular html image element in your control and set the "runat=server" property as so:
<img src="" runat="server" id="img_product" />
Then change your DataBind() method to do this instead:
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
lbl_title.Text = product.Title;
lbl_short.Text = product.Short;
lbl_date.Text = product.Date.ToShortDateString();
img_product.src= "\"data:image/jpg;base64,"+System.Convert.ToBase64String(product.Image1)+"\"";
base.DataBind();
}
And get rid of the HTTPHandler. You don't need it for this.
Change your handler so that it takes the id of the current product as a query string parameter. In the handler load the correct image data based on the parameter and write that instead.
well to conclude , for this case i think the best practice would be #icarus's answer ,
not the disregard #kmcc049's answer i just hadn't dug into it since it seemed like a more complicated architecture for my app.
in this case DROP THE HTTPHANDLER .
i saved the image's type , and data from the post file.
public enum ImageType : byte {jpg,jpeg,png,gif}
private byte[] Get_Image(HttpPostedFile file)
{
ImageType type = GetType(file.ContentType);
if (file.InputStream.Length <= 1)
return null;
byte[] imageData = new byte[file.InputStream.Length + 1 + 1];
file.InputStream.Read(imageData, 1, imageData.Length+1);
imageData[0] =(byte)type;
return imageData;
}
private ImageType GetType(string _type)
{
ImageType t = default(ImageType);
string s = _type.Substring(_type.IndexOf('/')+1).ToLower() ;
switch (s)
{
case "jpg": t = ImageType.jpg;
break;
case "jpeg": t = ImageType.jpeg;
break;
case "png": t = ImageType.png;
break;
case "gif": t = ImageType.gif;
break;
}
return t;
}
then i extracted and added it to the user control in my DataBind override(in my user control) :
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
img_main.Attributes.Add("src",Build_Img_Data(product.Image1));
base.DataBind();
}
private string Build_Img_Data(byte[] imageData)
{
ImageType type = (ImageType)imageData[0] ;
byte[] new_imageData = new byte[imageData.Length - 1];
Array.ConstrainedCopy(imageData, 1, new_imageData, 0, new_imageData.Length);
MemoryStream ms = new MemoryStream(new_imageData);
string base64String = string.Format("data:image/{0};base64,{1}",type.ToString(),Convert.ToBase64String(ms.ToArray()));
return base64String;
}

Categories

Resources