Hallo

Ich hab hier noch an ein weiteres Projekt gearbeitet wo ich euch die eine oder andere Technik draus erklären möchte.

Ich hab versucht den Montagezettel meiner Firma zu digitalisieren und mit neuen funktionen zu erweitern. Dafür hab ich erst einmal eine Excelversion von den Zettel angefertig. Mir war wichtig das es möglichs einfach gehalten wird und auch vom Aussehen des Zettel nicht viel ändert. (Die älteren Kollegen tun sich mit Änderungen immer schwer.) Ich hab leider keine Möglichkeit gefunden in eine Exceldokument ein Feld zum Unterschreiben einzufügen ohne Addons zu nutzen. Somit mußte ich das Dokument auch noch in Visual Studio in ein Formsprojekt nachbauen. Das Programm ist zusätzlich zum Unterschriftenfeld noch in der Lage den Zettel in einer Cloud zu speichern und die Daten aus den anderen Zettel in der Cloud auszulesen. Die ausgelesenen Daten kann man dann noch sich in einer Suchmaske anzeigen laßen. Achja und man kann das Dokument auch noch als PDF unterschrieben zum Kunden senden per Email. Das alles erfordert natürlich das Office installiert ist auf den Rechner wo das Program genutz wird.

Nun will ich euch aber mal ein paar Techniken etwas erklären, die ich genutz hab.

Unterschriftenfeld

Autocomplete einer Textbox mit SQL Abfrage

Exceldatein mit C# bearbeiten

Email mit C# versenden

Ein Verzeichnisbaum darstellen

Unterschriftenfeld  zum Anfang

Mit diesen Code hab ich Felder in mein Dokument was man mit Mouse oder bei Touchdisplay auch mit den Finger bemalen kann.

 public partial class Form2 : Form
{
private bool mouseDown; //ob Mauszeiger gedrückt wurde (zur Speicherung der Maus koordinaten)
private readonly List<Point> list; //Mauskoordinaten
private Bitmap bmp1; //Bitmap zum speichern des gezeichneten (Signature 1)
private Bitmap bmp2; //Bitmap zum speichern des gezeichneten (Signature 2)
.
        .
public Form2()
{
InitializeComponent();
this.list = new List<Point>(); //Liste für Koordinaten instanzzieren
if (File.Exists(@".\Resources\bmp1.png"))
{
this.bmp1 = new Bitmap(@".\Resources\bmp1.png");
}
else
{
this.bmp1 = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
if (File.Exists(@".\Resources\bmp2.png"))
{
this.bmp2 = new Bitmap(@".\Resources\bmp2.png");
}
else
{
this.bmp2 = new Bitmap(pictureBox2.Width, pictureBox2.Height);
}
pictureBox1.Image = bmp1;
pictureBox2.Image = bmp2;

Mit diesen Code bereite man Bitmaps vor für die beiden Pictureboxen die ich als Unterschriftenfelder nutze. In der If Anweisung wird geprüft ob es schon gespeicherte Unterschriften gibts, da man beim öffnen des Dokuments dadran weiterarbeiten kann. (Zum nachtragen der Fahrzeiten).

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
list.Add(new Point(e.X, e.Y));
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if(mouseDown)
{
mouseDown = false;
using (Graphics g = Graphics.FromImage(bmp1))
{
Draw(g);
g.Flush();
}
list.Clear();
pictureBox1.Invalidate();
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
list.Add(new Point(e.X, e.Y));
pictureBox1.Invalidate();
}
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (mouseDown)
Draw(e.Graphics);

}

private void Draw(Graphics g)
{
if (list.Count>0)
{
byte[] bs = new byte[list.Count];
bs[0] = (byte)System.Drawing.Drawing2D.PathPointType.Start;
for (int i = 1; i < list.Count; i++)
bs[i] = (byte)System.Drawing.Drawing2D.PathPointType.Line;

using (Pen p = new Pen(Color.Black, 2))
g.DrawPath(p, new System.Drawing.Drawing2D.GraphicsPath(list.ToArray(), bs));
}
}

Mit diesen Code wird bei gedrückter Maustaste auf den Picturebox die Koordinaten der Maus in einer Liste aufgenommen. Mit dieser Liste wird dann die Unterschrift auf den Feld dargestellt. 

Autocomplete einer Textbox nutzen mit SQL Abfrage: zum Anfang

Ich wollte in diesen Dokument für die Eingaben von Kunde und Standort gern eine kleine komfortoption einfügen. Bei der Eingabe erscheint nun eine Liste mit möglichen Eingaben wie man auch im Browser gewöhnt ist.

 private void AutoCompleteCustomer()
{
AutoCompleteStringCollection customercollection = new AutoCompleteStringCollection();
//Füllen der Auswahlliste für Kunden
try
{
using (SQLiteConnection con = new SQLiteConnection(Data.connectionstring))
{

con.Open();
SQLiteCommand command = new SQLiteCommand();

string query = @"SELECT Kundenname FROM ...";
command.CommandText = query;
command.Connection = con;

SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
customercollection.Add(reader[0].ToString());


}
}
reader.Close();
con.Close();

}


}
catch (SQLiteException ex)
{
MessageBox.Show(ex.Message);
}

txt_customer.AutoCompleteMode = AutoCompleteMode.Suggest;
txt_customer.AutoCompleteSource = AutoCompleteSource.CustomSource;
txt_customer.AutoCompleteCustomSource = customercollection;
}

Mit diesen Code wird eine AutoCompleteStringCollection aus der SQL-Abfrage gefüllt. Habe für die Datenbank eine eigene Klasse erstellt die die Datenbank erzeugt und wo auch der Connectionstring drin gespeichert ist. Nach der Abfrage wird der AutoCompleteMode von der Textbox noch aktiviert und gefüllt. Mit AutoCompleteMode.Suggest wird eine Liste mit Möglichkeiten angezeigt. Es gibt auch noch AutoCompleteMode.Append was dann die Möglichkeit direkt in der Textbox anzeigt bzw auch eine Kombination von beiden AutoCompleteMode.SuggestAppend. Mit AutoCompleteSource.CustomSource wird die AutoComplete Quelle auf eine Benutzerdefinierte gestellt und mit AutoCompleteCustomSource=customercollection wird die Liste zugeweisen.

Exceldatein mit C# bearbeiten zum Anfang

Ich habe für die Anweisungen für Excel eine eigen Klasse erzeug wo ich dann nur noch die Methoden nutzen muß. Aber erstmal zum Anfang. Um mit Excel arbeiten zu können muß man den Projekt erstmal den Verweis zuweisen. Das macht man mit Rechtsklick auf Verweis dann Verwei hinzufügen und unter Com dann Microsoft Excel 14.0 Object Library bzw Microsoft Office 14.0 Object Library. 

Verweis

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using Microsoft.Office.Core;
using System.Windows.Forms;

namespace IshidaForms
{
class ExcelData
{

Database Data = new Database();
public Dictionary<string, string> FieldDatabase = new Dictionary<string, string>();




public void Readofdocument(string file,bool update=false)
{
Excel._Application xlApp;
Excel.Workbook xlWorkbook;
Excel.Worksheet xlWorksheet;


FieldDatabase.Clear();

xlApp = new Excel.Application();

xlWorkbook = xlApp.Workbooks.Open(file);
xlWorksheet = xlWorkbook.Worksheets[1];

if (xlWorksheet.Cells[4, 4].Value != null)
{
FieldDatabase.Add("Kundenname",Convert.ToString (xlWorksheet.Cells[4,4].Value));
}
.
.
Data.ExceltoSQL(FieldDatabase,update);
xlWorkbook.Close();

}

Erstmal muß man mit using Excel = Microsoft.Office.Interlop.Excel; den neuen Verweiß auch zufügen. Ich nutze zum zwischenspeichern der Daten ein Dictionery da ich dort den Daten ein entsprechenden Key zuweisen kann und damit direkt auswählen kann. Zusätzlich ist auch meine Klasse für die Datenbank mit eingebunden. In der Methode werden dann noch entsprechend Variablen für die einzelne Teile von Excel zugewiesen. mit xlApp = new Excel.Application(); wird eine Instanz von Excel geöffnet. Mit xlWorkbook = xlApp.Workbook.Open(file); wird die entsprechende Datei geöffnet. Die Variable file wird beim Aufruf der Methode definiert und ist halt der entsprechende Pfad. Und zu guter letzt wird mit xlWorksheet = xlWorkbook.Worksheet[1]; noch die Tabelle ausgewählt. Mit der Anweisung xlWorksheet.Cells[1, 1].Value wird der Inhalt der Zelle A1 wiedergegeben bzw auch gesetzt. Mit der Anweisung FieldDatabase.Add("Kundenname",Convert.ToString (xlWorksheet.Cells[4,4].Value)); wird dem Dictionary den Key Kundenname und den Wert von der Zelle D4 als String zugewiesen.  Danach werden die Daten noch zur Datenbank geschickt und das Dokument mit xlWorkbook.Close() geschloßen.

if (FieldDatabase.ContainsKey("Taetigkeit_Installation"))
{
if (FieldDatabase["Taetigkeit_Installation"] == "WAHR")
{
xlWorksheet.OLEObjects("Installation").Object.Value = 1;
}
else
{
xlWorksheet.OLEObjects("Installation").Object.Value = 0;
}

}

In meinen Dokument gibts auch Felder zum Ankreuzen. Mit der Anweisung xlWorksheet.OLEObjects("Name").Object.Value kann ich den Zustand der Box steuern oder lesen. 

 xlWorksheet.Shapes.AddPicture(bmp2, MsoTriState.msoFalse, MsoTriState.msoCTrue, 425f, 1050f, 335f, 30f);

mit der Anweisung kann man ein Bild hinzufügen. Mit den letzten 4 Werte bestimmt man die Position und die Größe. Der Erste Wert in der Klammer ist der Pfad zum Bild.

Und letztendlich mit xlWorkbook.Save() kann man das alles noch speichern. Zusätzlich hab ich auch noch eine Funktion die Exceltabelle in eine PDF zu wandeln. Das macht man dann mit der Anweisung xlWorkbook.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypePDF, path);.

Email mit C# verschicken zum Anfang

Mit meinen Program ist es auch möglich eine Email mit Anhang zu versenden. Den Emailtext kann muß man vor den Versenden in den Option vom Program definieren.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Windows.Forms;

namespace Forms
{
class Outlookdata

{
string emailbody =@""+ Properties.Settings.Default.emailbody;

public bool SendMail(string emailadress,string pathAttachment,string subject)
{
pathAttachment += @"\Montagezettel.pdf";
try
{
Outlook.Application oApp = new Outlook.Application();
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMsg.HTMLBody = emailbody;
string sDisplayName = "Nachweis_Montageleistung";
int iPosition = (int)oMsg.Body.Length + 1;
int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
Outlook.Attachment oAttach = oMsg.Attachments.Add(pathAttachment, iAttachType, iPosition, sDisplayName);
oMsg.Subject = subject;
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(emailadress);
oRecip.Resolve();
oMsg.Send();
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
return true;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}

}
}
}

Erstmal wird mir using Outlook = Microsoft.Office.Interlop.Outlook; die Verwendung von Outlook ermöglicht. Zuvor muß natürlich der Verweis wie im Excel Abschnitt erklärt zugeweisen werden. Den Text für die Email laß ich wie gesagt in Optionen definieren und ist dort in einer Resource gespeichert die ich mit Properties.Settings.Default.emailbody abrufe. Dann wird erstmal wie bei Excel mit Outlook.Application oApp = new Outlook.Application(); eine Instanz von Outlook erzeugt. Mit Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem); wird eine Email erzeugt. Mit oMsg.HTMLBody = emailbody; wird der Text aus der Option der Mail zugewiesen. Mit Outlook.Attachment oAttach = oMsg.Attachments.Add(pathAttachment, iAttachType, iPosition, sDisplayName); wird der Anhang definiert. Mit oMsg.Subject wird der Betreff zugeweisen. Und mit den Befehlen Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients; und Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(emailadress); wird noch eine Emailaddress hinzugefügt. Den zweiten Befehl kann man natürlich mehrmals nutzen für weitere Emailaddressen. Letzendlich wird dann mit oMsg.Send(); die Email versendet.

Ein Verzeichnisbaum erstellen: zum Anfang

In meiner Suchmaske ist ein Treeview der das Verzeichnis wo die Montagezettel sind darstellt und gleichzeitig auch noch die Daten von den Zetteln auslesen läßt. Mit diesen Code wird das alles bewerkstelligt.

 private void Form4_Load(object sender, EventArgs e)
{
readfromdatabase();
treeView1.Nodes.Clear();
if (boxpath != "" && Directory.Exists(boxpath))
{
Cursor = Cursors.WaitCursor;
LoadDirectory(boxpath);
Cursor = Cursors.Default;
}
else
MessageBox.Show("Bitte in Einstellung einen Path für den Boxordner einstellen");

}

public void LoadDirectory(string Dir)
{
DirectoryInfo di = new DirectoryInfo(Dir);
TreeNode tds = treeView1.Nodes.Add(di.Name);
tds.Tag = di.FullName;
tds.StateImageIndex = 0;
LoadFiles(Dir, tds);
LoadSubDirectories(Dir, tds);
}

private void LoadSubDirectories(string dir, TreeNode td)
{
string[] subdirectoryEntries = Directory.GetDirectories(dir);
foreach (string subdirectory in subdirectoryEntries)
{
DirectoryInfo di = new DirectoryInfo(subdirectory);
TreeNode tds = td.Nodes.Add(di.Name);
tds.StateImageIndex = 0;
tds.Tag = di.FullName;
LoadFiles(subdirectory, tds);
LoadSubDirectories(subdirectory, tds);

}
}

private void LoadFiles(string dir, TreeNode td)
{
string[] Files = Directory.GetFiles(dir, "*.*");
foreach (string file in Files)
{
FileInfo fi = new FileInfo(file);
TreeNode tds = td.Nodes.Add(fi.Name);
tds.Tag = fi.FullName;
tds.StateImageIndex = 1;

if (fi.Name == Inputdata)
{
if (boxview.ContainsKey(fi.FullName))
{
if (boxview[fi.FullName]!=fi.LastWriteTime.ToString())
{
try
{
using (SQLiteConnection con = new SQLiteConnection(Data.connectionstring))
{
con.Open();
SQLiteCommand command = new SQLiteCommand();

string query = @"UPDATE boxview SET lastModifiy='"+fi.LastWriteTime.ToString()+"' WHERE Path='"+fi.FullName+"'";
command.CommandText = query;
command.Connection = con;
command.ExecuteNonQuery();

con.Close();
}


}
catch (SQLiteException e)
{
MessageBox.Show(e.Message);
}
excel.Readofdocument(fi.FullName,true);

}
}
else
{
using (SQLiteConnection con = new SQLiteConnection(Data.connectionstring))
{
con.Open();
SQLiteCommand command = new SQLiteCommand();

string query = @"INSERT INTO boxview (Path , lastModifiy) VALUES (@Path, @lastModifiy)";
command.CommandText = query;
command.Connection = con;
command.Parameters.AddWithValue("@Path", fi.FullName);
command.Parameters.AddWithValue("@lastModifiy", fi.LastWriteTime.ToString());
command.ExecuteNonQuery();

con.Close();
}
excel.Readofdocument(fi.FullName);

}






}
}
if (cmb_Ansicht.SelectedIndex == 1)
{
readfromsql(@"SELECT Kundenname, Standort, Techniker, Serviceauftrag, Datum1, Maschine1, Seriennummer1, Maschine2, Seriennummer2, Maschine3, Seriennummer3, Maschine4, Seriennummer4, Maschine5, Seriennummer5, Maschine6, Seriennummer6, Taetigkeit FROM ishida");
}
else
{
readfromsql(@"SELECT * FROM ishida");
}
}

private void treeView1_MouseMove(object sender, MouseEventArgs e)
{
TreeNode theNode = this.treeView1.GetNodeAt(e.X, e.Y);
if (theNode != null && theNode.Tag != null)
{
if (theNode.Tag.ToString() != this.toolTip1.GetToolTip(this.treeView1))
this.toolTip1.SetToolTip(this.treeView1, theNode.Tag.ToString());

}
else
{
this.toolTip1.SetToolTip(this.treeView1, "");
}
}
private void treeView1_MouseDoubleClick(object sender, MouseEventArgs e)
{

TreeNode theNode = this.treeView1.GetNodeAt(e.X, e.Y);
if(theNode!=null && theNode.Tag != null)
{

if (File.Exists(theNode.Tag.ToString()))
System.Diagnostics.Process.Start(theNode.Tag.ToString());
}

}

Erstmal müßen mit using System.IO und using System.Data.SQLite verweis hinzugefügt werden um alles ausführen zu können. Mit der Funktion readfromdatabase() wird ein Dictionary gefüllt mit den Daten wann die Datei das letztemal geändert wurde nach den Stand des letzten auslesen. Das ist zum verhindern das jede Datei jedesmal ausgelesen wird. (Die Excel Methode ist nicht grad sehr schnell) Während dann die Funktion LoadDirectory() ausgeführt wird, wird der Cursor der Maus auf den warte Cursor geändert. Mit LoadDirectory() und LoadSubDirectories() werden nun die Verzeichnisse den Baum hinzugefügt. Mit Loadfiles() dann noch die Datein zugewiesen. Dort wird dann auch gleich geschaut ob es sich um die Exceldatei handelt. Wenn die Datei aktueller als die schonmal ausgelesen ist wird die Datenbank aktualisiert und falls noch nicht vorhanden werden die Daten der Datenbank hinzugefügt. Anschließend wird noch das Datagrid je nach Auswahl mit Daten gefüttert. Mit der Funktion von treeview1_MouseMove() wird noch ein Tooltip mit den kompletten Pfad angezeigt sofern man über einer Datei ist. Mit der Funktion treeView1_MouseDoubleClick() kann man mit ein Doppelklick der Maus die Datei auch direkt öffnen.

 

So hoffe ihr könnt mit den Beschreibungen was anfangen und vielleicht helfen auch einge eure Projekte weiter.

Gruß Shadow

P.S.: Auch hier könnt ihr die Tippfehler gern für euch behalten :D

Wir benutzen Cookies

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell für den Betrieb der Seite, während andere uns helfen, diese Website und die Nutzererfahrung zu verbessern (Tracking Cookies). Sie können selbst entscheiden, ob Sie die Cookies zulassen möchten. Bitte beachten Sie, dass bei einer Ablehnung womöglich nicht mehr alle Funktionalitäten der Seite zur Verfügung stehen.