How to write into same xml file from two pages? - c#

I have Single.cs and Periodic.cs files, which have Button_Click events, and user should add some information into same file by pressing these buttons. Implementation of Button_Click is almost same, this is why I show only one them.
using System.IO;
//.........
namespace ModernUIApp1.Pages
{
public partial class Home : UserControl
{
private void Button_Click(object sender, RoutedEventArgs e)
{
// this is how i get required path
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
string script = "script";
string path_scriprt1 = Path.Combine(_directoryName1, script+".xml");
cur_script.Add(new XElement("Single_Request" + Convert.ToString(num),
new XElement("numRequest", TxtBlock_numRequest.Text),
));
cur_script.Save(path_scriprt1);
num++; // I use this to create unique name
}
XElement cur_script = new XElement("Requestes");
int num = 1;
}
}
Eventually, user can push buttons many times, and this code will work fine if I dont use these buttons at the same time. Because otherwise it simply overwrites existing information. So the problem is to make this XElement cur_script = new XElement("Requestes"); global. Or do you have some other ways out?

The real issue is that you need to avoid concurrency issue here. What if you have two persons try to update the same file and the following sequences occurs:
User 1 open and load the file;
User 2 open and load the file;
User 1 modify the xml and save it;
User 2 modify the xml and save it;
In this case the change made by user 1 will be lost.
To avoid this problem you want to keep the file open until your have saved it. For example:
using (FileStream stream =
File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
....load xml, modify it, and save it
}

public void WriteToDoc(XmlDocument doc, XElement element)
{
// this method can reside somewhere outside.
// some generic doc loader can load the doc
// add element to doc
}
public void OnButton1Click(object sender, RoutedEventArgs e)
{
// do something with element
WriteToDoc( mydoc, myNewElement)
}
public void OnButton2Click(object sender, RoutedEventArgs e)
{
// do something else with element
WriteToDoc( mydoc, myNewElement)
}
V2
public class ElementAdder
{
public static void WriteToDoc(string path, XElement element)
{
// load doc based on path
// add element to doc
}
}
public void OnButton1Click(object sender, RoutedEventArgs e)
{
// do something with element
string path = ConfigMan.GetDocPath();
ElementAdder.WriteToDoc(path, myNewElement);
}
public void OnButton2Click(object sender, RoutedEventArgs e)
{
// do something else with element
string path = ConfigMan.GetDocPath();
ElementAdder.WriteToDoc(path, myNewElement);
}

Thank you for help, but I solved problem on my own. I just used tips how to write into same xml-file, this way:
XDocument Requestes = XDocument.Load(path_scriprt1);
XElement newElement = new XElement("Single_Request" + Convert.ToString(num),
new XElement("numRequest", TxtBlock_numRequest.Text),
new XElement("IDWork", TxtBlock_IDWork.Text),
new XElement("NumObject", TxtBlock_NumObject.Text),
new XElement("lvlPriority", CmbBox_lvlPriority.Text),
new XElement("NumIn1Period", TxtBlock_NumIn1Period.Text)
);
Requestes.Descendants("Requestes").First().Add(newElement);
Requestes.Save(path_scriprt1);

Related

How to copy multiple items to clipboard history in c#?

I'm using the clipboard class from Win API (Windows.ApplicationModel.DataTransfer.Clipboard). When I try to copy multiple items one by one to the clipboard history, it gets overwritten by the recent item. I want to store every item I copy onto the clipboard history. My clipboard history is enabled and I tried using all of the set methods from clipboard including the SetText method from (System.Windows.Clipboard) and all of which overwrites instead of adding to history.
private void UpdateClipboardOnProfileDropDownClosed(object sender, EventArgs e)
{
Clipboard.ClearHistory();
using (var db = new LiteDatabase(Path.Combine(documents, "Auto Paste Clipboard", "data.db")))
{
var collection = db.GetCollection<ClipboardProfile>("clipboard");
var clipboard = collection.FindOne(x => x.Profile == ProfileComboBox.Text);
clipboard.Clipboard.Reverse();
MessageBox.Show(clipboard.Clipboard.Count.ToString());
foreach (var item in clipboard.Clipboard)
{
DataPackage data = new DataPackage
{
RequestedOperation = DataPackageOperation.Copy
};
data.SetText(item);
Clipboard.SetContent(data);
}
}
}
It takes some delays for Clipboard history to save the current item. Therefore, you could try to add a delay when an item is added.
Please check the following code as a sample:
private async void Button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if(Clipboard.IsHistoryEnabled())
{
List<string> lists=new List<string>{ "1","2","3","4","5","6","7","8","9","10"};
foreach(var item in lists)
{
DataPackage dataPackage = new DataPackage();
dataPackage.SetText(item);
Clipboard.SetContent(dataPackage);
await Task.Delay(250);
}
}
}
Note, if these items are not all added, you could increase the delay time.

Using XML elements

I have working code that I'd simply like to reference parts of multiple times in other area's of my program, however my problem seems to be with anonymous types (var)
here's a section of my program that loads my XML file
string path = "Data//handling4.meta";
var doc = XDocument.Load(path);
var items = doc.Descendants("HandlingData").Elements("Item");
var query = from x in items
select new
{
HandlingName = (string)x.Element("handlingName"),
HandlingType = (string)x.Element("HandlingType"),
Mass = (decimal?)x.Element("fMass").Attribute("value"),
InitialDragCoeff = (decimal?)x.Element("fInitialDragCoeff").Attribute("value"),
PercentSubmerged = (decimal?)x.Element("fPercentSubmerged").Attribute("value"),
DriveBiasFront = (decimal?)x.Element("fDriveBiasFront").Attribute("value")
};
This code works great, I can also use a foreach loop like this to reference items
foreach(var HandlingName in query)
{
string Names = HandlingName.HandlingName;
}
So my question is, how to reference that to another place in the program? for e.g.
private void button1_Click(object sender, EventArgs e)
{
comboBox1.Items.Add( Names);
}
The above code throws the error 'Names does not exist in the current context'
I need for my comboBox to display each handling name, but it fails because anonymous types cannot be referenced. Am I doing something wrong, or am I just not using the incorrect method? Thanks
Edit: Also to mention that the XML is needing to be referenced in multiple parts of the program, button click even shows the values in a DataGridView for example. If I could make a class to load the XML, then each element in different area's of the program that'd be ideal, rather than loading the hefty block of code each time
the XML is needing to be referenced in multiple parts of the program,
But all your variables are local. You need to store something in a Form fiead or property.
// outside any method:
private List<string> names = new List<string>();
void myLoadMethod()
{
...
foreach(var HandlingName in query)
{
//string Names = HandlingName.HandlingName;
Names.Add(HandlingName.HandlingName);
}
}
private void button1_Click(object sender, EventArgs e)
{
comboBox1.Items.Add( Names);
}

Simple yet frustrating Listbox and Texbox search again

I have spent few days searching everywhere for a solution to this.
This is for C# with Visual Studio 2013 (ya, I am a newbie):
two textboxes (Last name and First Name) and a listbox with 5 names (Higgins M, Higgins J, King J, Tran A, Dempsey S). I set listbox property as sorted.
if I select Higgins J in listbox, then the word Higgins should appear in Last Name textbox and J should appear in First Name textbox.
if I type Higgins in Last Name textbox, Higgins J should be the selected item in listbox (Higgins J will be selected before Higgins M). If I type M in the First Name textbox, the selected item should change from Higgins J to Higgins M.
but....here are the problems that made me decide to create an account here:
If I type Hi or Hig instead of Higgins, it has to stay that way, it does not become Higgins in the textbox. Only the index/highlight in listbox is changed, not the entry in textbox (whatever I type in the textbox stays). I suspect the events that I use are the reason I cannot get this done. Textbox_textchanged and listbox_selectedindexchanged. So whatever I do in one event will automatically triggers the other. I have tried changing the events, but so far the result simply worse. Using: if (LastName_textbox.Text = "") did not help either.
How do I combine Last Name and First Name as one index?
I apologise if this question has appeared or sounded ambiguous. I suppose I do not know how to phrase the search to get something similar to my problem and English is not my first language. Any help is very much appreciated .Thanks.
Here is part of the codes:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Project
{
public partial class frmContact : Form
{
//declare file to save all contacts
private string fileName = Directory.GetCurrentDirectory() + "\\Contacts.txt";
//create temporary file for updating and deleting contacts
private string newContacts = Directory.GetCurrentDirectory() + "\\newContacts.txt";
public frmContact()
{
InitializeComponent();
}
private void frmContact_Load(object sender, EventArgs e)
{
//create Contacts.txt if it does not exist
if (!File.Exists(fileName))
{
File.Create(fileName).Close();
MessageBox.Show("New " + fileName +" Has Been Created");
tbLast.Select();
}
//if file already exists
else
{
StreamReader readOb = new StreamReader(fileName);
using (readOb)
{
while (!readOb.EndOfStream)
{
string rdLine = readOb.ReadLine(); //read data in file by line
string[] tmpArr = rdLine.Split(',');
lbContact.Items.Add(tmpArr[0] + "," + tmpArr[1]);
}
tbLast.Select();
}
}
}
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
//show details of contact selected in listbox
string findNames = lbContact.GetItemText(lbContact.SelectedItem);
StreamReader obRead = new StreamReader(fileName);
using (obRead)
{
while (!obRead.EndOfStream)
{
string rdLine = obRead.ReadLine();
if (rdLine.StartsWith(findNames))
{
string[] tmpArr = rdLine.Split(',');
tbLast.Text = tmpArr[0];
tbFirst.Text = tmpArr[1].Trim();
tbAddr.Text = tmpArr[2].Trim();
tbSub.Text = tmpArr[3].Trim();
tbPost.Text = tmpArr[4].Trim();
tbEmail.Text = tmpArr[5].Trim();
tbPhone.Text = tmpArr[6].Trim();
tbMob.Text = tmpArr[7].Trim();
}
}
lbContact.SelectedIndex = lbContact.FindString(findNames);
}
}
private void tbLast_TextChanged(object sender, EventArgs e)
{
lbContact.SelectedItem = lbContact.FindString(tbLast.Text);
}
A simple (but kind of ugly solution) would consist in using a boolean value to inform your lbContact_SelectedIndexChanged method that the index was manually changed thanks to the code. A class member would do the job, something like:
private bool fromCode;
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
if (fromCode)
return;
// Do the job
}
private void tbLast_TextChanged(object sender, EventArgs e)
{
fromCode = true;
lbContact.SetSelected(lbContact.FindString(tbLast.Text), true);
fromCode = false;
}
[Personal remark]
I would also create a Contact struct/class to store your information along with a collection in your form so that you only have to access your file twice:
At loading, so that you can populate your collection
At closing, so that you can save the changes to your file
[Update]
My last remark can be not relevant as I do not have the context in which you are developing your application, that's why I said it was a personal point of view, you don't have to do it.
[Update 2]
What you can do to avoid access your file each time your lbContact_SelectedIndexChanged event is called:
Create a structure or a class to store your contacts information (firstname, lastname, adress, ...)
Create a collection (as a class member of your form) that will contain the contacts (like a List<Contact>)
In your frmContact_Load method, fill this collection with the data contained in the file instead of populating your listbox
So that in your lbContact_SelectedIndexChanged method you will search inside the collection instead of opening your file
Your Add() and Delete() operations must also modify the collection and not the file anymore
Remember to save your collection back to your file at application closing
Hope it helped.
I found the solution (for whoever encounters similar problem), the answer is in the textbox.focused :) and combined with listbox.setselected from Tim.
private void tbLast_TextChanged(object sender, EventArgs e)
{
if (tbLast.Focused && tbLast.Text != "")
{
if (lbContact.FindString(tbLast.Text) > -1)
{
lbContact.SetSelected(lbContact.FindString(tbLast.Text), true);
}
}
}
private void lbContact_SelectedIndexChanged(object sender, EventArgs e)
{
//show details of contact selected in listbox
string findNames = lbContact.GetItemText(lbContact.SelectedItem);
StreamReader obRead = new StreamReader(fileName);
using (obRead)
{
while (!obRead.EndOfStream)
{
string rdLine = obRead.ReadLine();
if (rdLine.StartsWith(findNames))
{
string[] tmpArr = rdLine.Split(',');
if (!tbLast.Focused)
{
tbLast.Text = tmpArr[0];
tbFirst.Text = tmpArr[1].Trim();
tbAddr.Text = tmpArr[2].Trim();
tbSub.Text = tmpArr[3].Trim();
tbPost.Text = tmpArr[4].Trim();
tbEmail.Text = tmpArr[5].Trim();
tbPhone.Text = tmpArr[6].Trim();
tbMob.Text = tmpArr[7].Trim();
}
}
}
lbContact.SelectedIndex = lbContact.FindString(findNames);
}
}

C# Streamreader problems

I'm building a program that has you input a number and remembers it when you re-open the program. It uses a text file to save the number in. I'm using streamreader to read the text file to get the number you entered last, but it always throws an exception. Where should I put the text file or change my code so it can read and edit the text? Here is my code:
namespace Cookie_Clicker
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void tb_TextBox(object sender, RoutedEventArgs e)
{
}
private void add_Click(object sender, RoutedEventArgs e)
{
try
{
using (StreamReader sr = new StreamReader("cookies.txt"))
{
int data = Convert.ToInt16(sr.ReadToEnd());
tb.Text = Convert.ToString(data + 1);
}
}
catch (Exception)
{
MessageBox.Show("Your cookie text file is missing!");
}
}
private void reset_Click(object sender, RoutedEventArgs e)
{
}
}
}
Every time it says "Your cookie text file is missing!"
Problem 1: You are not specifying proper path of your input file.
Solution 1: You need to get the Currentpath of your application from where it is running and then combine it with the filename using Path.Combine() method.
Try This:
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"cookies.txt");
using (StreamReader sr = new StreamReader(path))
{
int data = Convert.ToInt16(sr.ReadToEnd());
tb.Text = Convert.ToString(data + 1);
}
Suggestion : You need to always display the Error message in Catch block to identify the problem.
You can call ToString() on Exception object to get the complete exception info.
catch (Exception ex)
{
MessageBox.Show(ex.ToSTring();
}
To answer your question:
Where should I put the text file...?
You haven't specified a path to cookies.txt so the program will look for it in the same directory where it's running. If you change cookies.txt to include a path, for example C:\dev\cookies.txt, then you can store the file wherever you like.
That will allow you to get past the file not found error and address any other problems you have in there.

Save Contents Of a TextBox To a File

I'm developing an application that has a TextBox. I want to write its contents to a file, but how can I do this?
There are many ways to accomplish this, the simplest being:
using(var stream = File.CreateText(path))
{
stream.Write(text);
}
Be sure to look at the MSDN page for File.CreateText and StreamWriter.Write.
If you weren't targeting the .NET Compact Framework, as your tags suggest, you could do even simpler:
File.WriteAllText(path, string);
System.IO.File.WriteAllText("myfile.txt", textBox.Text);
If you're stuck on some brain-dead version of the BCL, then you can write that function yourself:
static void WriteAllText(string path, string txt) {
var bytes = Encoding.UTF8.GetBytes(txt);
using (var f = File.OpenWrite(path)) {
f.Write(bytes, 0, bytes.Length);
}
}
Try this:
using System.Text;
using System.IO;
static void Main(string[] args)
{
// replace string with your file path and name file.
using (StreamWriter sw = new StreamWriter("line.txt"))
{
sw.WriteLine(MyTextBox.Text);
}
}
Of course, add exception handling etc.
For a richTextBox, you can add a "Save" button for this purpose. Also add a saveFileDialog control from Toolbox, then add following code in button's click event.
private void button1_Click(object sender, EventArgs e)
{
DialogResult Result = saveFileDialog1.ShowDialog();//Show the dialog to save the file.
//Test result and determine whether the user selected a file name from the saveFileDialog.
if ((Result == DialogResult.OK) && (saveFileDialog1.FileName.Length > 0))
{
//Save the contents of the richTextBox into the file.
richTextBox1.SaveFile(saveFileDialog1.FileName);
}
}

Categories

Resources