Save and Load ListView content - c#

I am writing an app in C# winForm, and I am using ListView to store some data.
I need to save this list of item when the form is closed and load it again when the form is opened again.
This is the code to add a new element on the list:
string[] timeitem = new string[2];
timeitem[0] = txtDescription.Text;
timeitem[1] = msktime.Text;
ListViewItem lvi = new ListViewItem(timeitem);
lstTimes.Items.Add(lvi);
What is the best way to save and load this list? I do not need a Dialog for the user, this list should be saved and loaded automatically each time the user open the form that contains the ListView item. I am open to use either .txt or xml file, whatever is the best/more easy to handle.

You could write a simple helper class for that:
class ListItemsHelper
{
private const string FILE_NAME = "items.dat";
public static void SaveData(Items items)
{
string data = SerializeItems(items);
File.WriteAllText(GetFilePath(), data);
}
public static Items LoadData()
{
string data = File.ReadAllText(GetFilePath());
return DeserializeItems(data);
}
private static string GetFilePath()
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILE_NAME);
}
private static string SerializeItems(Items items)
{
//Do serialization here
}
private static Items DeserializeItems(string data)
{
//Do deserialization here
}
}
Use:
ItemsStateHelper.SaveData(items);
Items data = ItemsStateHelper.LoadData();
Additionally, you would have to include some exception handling and choose where you want to save the file. In the code i posted it is saving on folder where the exe file is located.

Related

How to create a custom file name with input from another form?

I'm quite new to Visual Studio and currently trying to create an application with several forms. I have a "menu" form with a panel in the middle which shows all the other forms when I click on the respective button. I also have a text box where the user writes their ID, and a method to create a folder and a file in it with the ID as part of the folder/file names.
On each "subform", I also have a label which shows the ID (input from MenuForm). So far, so good. What I'm trying to do is to create a method which sets the right directory (aka the folder with the ID) and creates a new file with the extension "_ID.csv".
My problem right now is that I'm pulling the "ID" form MenuForm, create a new string variable with the value of the ID, and then, in another method, try to use the newly created variable to give as an argument for the creation of a new file. I'm not getting any error, but it's not working either...
public partial class Form2 : Form
public string _IDForm1
{
set { LblIDForm2.Text = value;}
}
private void Schreiben(FileMode fm)
{
string VPN = "VPN";
string id = LblIDForm2.Text;
try
{
string destinationFolder = #"..\XVR\" + id;
Directory.CreateDirectory(destinationFolder);
Directory.SetCurrentDirectory(destinationFolder);
string fileName = LblIDForm2.Text;
FileStream fs = new(fileName + "_Sali.csv", fm);
StreamWriter sw = new(fs);
sw.WriteLine($"{VPN};{id}");
sw.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

View all file from a list

I´m working on a project that uses Caliburn micro in wpf C#.
I´m in the process that I want to rewrite my method ReadMediaFile() so it displays all files in a folder in a list.
My method looks lite this:
private void ReadMediaFile()
{
string result;
_movieviewmodel = new MoviesViewModel();
string[] filePaths = Directory.GetFiles(#"C:/Users/v80770/Desktop/Movies/");
foreach (var file in filePaths)
{
result = Path.GetFileName(file);
_movieviewmodel.MovieName = result;
}
AddItem(_movieviewmodel);
}
When I debug the program all the files show in filePaths but only one shows in my list.
The AddItem is located in a class called TreeViewBase (belongs to caliburn micro I think) and it looks like this:
public void AddItem(T item)
{
_dispatcher.SmartInvoke(() => Items.Add(item));
}
I got the movie files viewing in my list but my MediaUri binding in view is bind against a specific path file but I want it to change dependent on what I choose
I tried to edit the binding to this:
string test = _movieviewmodel.MovieName;
MediaUri = new Uri(test);
But only get a exception "System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'"
Picture of Uri
New Uri code:
_movieviewmodel.MovieFilePath = #"C:/Users/v80770/Desktop/Movies/";
string test = _movieviewmodel.MovieFilePath;
MediaUri = new Uri(test + _movieviewmodel.MovieName);
But it always shows the same movie and my _movieviewmodel.MovieName does not change name dependent which movie I choose, it always is the same movie.
The creation of a MoviesViewModel item object and AddItem(_movieviewmodel); must be inside foreach, otherwise it would add only the last item:
foreach (var file in filePaths)
{
var movieviewmodel = new MoviesViewModel();
movieviewmodel.MovieName = Path.GetFileName(file);
AddItem(movieviewmodel);
}
or
foreach (var file in filePaths)
{
AddItem(new MoviesViewModel
{
MovieName = Path.GetFileName(file)
});
}

How I can use a DataObject on MacOS (Drag and Drop files)

DataObject is part of System.Windows and not available in Xamarin.Mac. So how can I do a workaround. I want to create a drag n drop function with a external file. On Windows I can do this with a DataObject.
I already searched for alternatives, tried it with NSUrl but without success.
Drag into your app:
All NSView-based classes have a RegisterForDraggedTypes method that you pass what you want to accept (in your case a UTType.FileURL as you are passing something into the app, assumably a file from Finder).
So in this case I have a NSTableView that accepts files, adds them the the table and fires an notification that causes an NSTask to process them (it is a FFMPEG-based task).
tableView.RegisterForDraggedTypes(new string[] { UTType.FileURL };
From there it depends upon the type of NSView you are dragging into, but for example with an NSTableView, you assign its data delegate a NSTableViewDataSource subclass which you have overridden ValidateDrop and AcceptDrop.
In NSTableViewDataSource.ValidateDrop you confirm if the drop contains file(s) that you will accept. In this case, as long as it is a file of any type I accept:
public override NSDragOperation ValidateDrop(NSTableView tableView, NSDraggingInfo info, nint row, NSTableViewDropOperation dropOperation)
{
var operation = NSDragOperation.Copy;
using (var pasteBoard = info.DraggingPasteboard)
{
foreach (var item in pasteBoard.PasteboardItems)
{
if (!item.Types.Contains(UTType.FileURL))
{
operation = NSDragOperation.None;
}
item.Dispose();
}
}
return operation;
}
In in NSTableViewDataSource.AcceptDrop, you actually process the files from the drop.
public override bool AcceptDrop(NSTableView tableView, NSDraggingInfo info, nint row, NSTableViewDropOperation dropOperation)
{
using (var pasteBoard = info.DraggingPasteboard)
{
if (pasteBoard.PasteboardItems.Length > 0)
{
var range = new NSRange(-1, 0);
foreach (var item in pasteBoard.PasteboardItems)
{
if (item.Types.Contains(UTType.FileURL))
{
var finderNode = item.GetStringForType(UTType.FileURL);
// you have a file from macOS' finder, do something with it, assumable in a table view you would add a record/row....
var url = NSUrl.FromString(finderNode);
// url has the file extension, filename, full path, etc...
Post a notification / Add a task to GCD / etc...
}
item.Dispose();
}
return true;
}
}
return false;
}
Drag out of your app:
Lets assume you have an NSView subclass that you wish to drag a "file" out of and into Finder or any app that accepts file drops. Implement the interfaces; INSDraggingSource and INSPasteboardItemDataProvider on your NSView subclass.
In the MouseDown event, start your drag for UTType.FileURL types:
public override void MouseDown(NSEvent theEvent)
{
var pasteboardItem = new NSPasteboardItem();
pasteboardItem.SetDataProviderForTypes(this, new string[1] { UTType.FileURL });
var draggingItem = new NSDraggingItem(pasteboardItem);
var fileDragIcon = new NSImage("theDraggingIcon.png");
draggingItem.SetDraggingFrame(new CoreGraphics.CGRect(0,0,40,40), fileDragIcon);
BeginDraggingSession(new NSDraggingItem[1] { draggingItem }, theEvent, this);
}
In the ProvideDataForType place the file url onto the pasteboard:
public void ProvideDataForType(NSPasteboard pasteboard, NSPasteboardItem item, string type)
{
if (type == UTType.FileURL )
{
var url = new NSUrl("/Users/Sushi/Desktop/StackOverflow.png", false);
url.WriteToPasteboard(pasteboard);
}
}
Note: That is just one way to transfer a file, there are three other file drag transfers, you can also provide an array of urls, a promise to create the file yourself later and actually inserting the file's data into the pasteboard.

dictionary error item with the same key has already been added

I'm trying to read every #define in a C++ header, and display an editor for each of the values, so I can quickly redefine the constants.
I'm trying to parse the file, getting each item on the left side to be key. I want to display the value on the left, edit the values and save back out. Currently, when I save my file it messes up the format.
This is the code i currently have :
private String header;
private Dictionary<String, String> tokens;
private String file = Properties.Settings.Default.path_location;
public TextBox elf_naparm_zombie_developer;
public harrs_gsh_editor(string file)//TextBox elf_naparm_zombie_developer
{
Properties.Settings.Default.path_location = file;
Properties.Settings.Default.Save();
loadweapon();
// this.elf_naparm_zombie_developer = elf_naparm_zombie_developer;
}
public void loadweapon()
{
this.tokens = File.ReadLines(this.file)
.Select(line => Regex.Match(line, #"^\s*#define\s+(.+?)(\s+(.+?))?((\s*//)|$)"))
.Where(m => m.Success && m.Groups[3].Success)
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[3].Value);
}
public String Search(String name)
{
foreach (KeyValuePair<String, String> pair in tokens)
{
if (pair.Key == name)
return pair.Value;
}
return null;
}
public void Set(String key, String val)
{
tokens[key] = val;
}
public void Save(String file)
{
using (StreamWriter sw = new StreamWriter(File.OpenWrite(file)))
{
sw.Write(header);
foreach (KeyValuePair<String, String> pair in tokens)
{
sw.Write("\r\n" + pair.Key + "#define " + pair.Value);
}
}
}
public void Save()
{
this.Save(file);
}
The issue I have is when I save it back, it messes up the file and removes the #define. What im trying to do is just change the value and write it back to the program with changed value
this is the file i want to edit
So what im trying to do is load up the selected key and display the value witch i have managed to do with this code i created but the issue im having is writing it back
the code i use to load and populate the text box
namespace Harry_s_Template_Editor
{
public partial class Form1 : Form
{
harrs_gsh_editor elfghc;
string path = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"/hb21_zm_ai_napalm.gsh";
public Form1()
{
InitializeComponent();
elfghc = new harrs_gsh_editor(path);//TextBox elf_naparm_zombie_developer
elf_naparm_zombie_developer = elf_naparm_zombie_developer;
// MessageBox.Show(path);
}
private void button1_Click(object sender, EventArgs e)
{
elfghc.loadweapon();
this.elf_naparm_zombie_developer.Text = elfghc.Search("NAPALM_ZOMBIE_DEVELOPER_DEBUG_PRINTS");
elfghc.Set("NAPALM_ZOMBIE_DEVELOPER_DEBUG_PRINTS", elf_naparm_zombie_developer.Text);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
elfghc.Set("NAPALM_ZOMBIE_DEVELOPER_DEBUG_PRINTS", elf_naparm_zombie_developer.Text);
elfghc.Save(path);
}
}
}
when i save out the file i now get this error when i try to load the program again
error
thanks in advance Yuki
file when saved back
Original answer:
Why are you writing it back to the file in this order: sw.Write("\r\n" + pair.Key + "#define " + pair.Value);? Shouldn't the #define come first on the line after \r\n? I would have thought it should be something like this: sw.Write("\r\n#define " + pair.Key + " " + pair.Value);
New answer (the question has changed)
There are two problems with what you are doing:
You are writing key/value pairs back to a file, ignoring the headers and credits that were in the original file. If you're happy to strip those out then that's fine, but it sounds like this is important to you. So instead you need to read the file, find the keys in the file, then update the values and save the updated file back to disk. That's a harder problem than simply writing a bunch of key/value pairs to a file.
The second issue is the way you are writing the file back to disk. According to this MSDN page, File.OpenWrite has the following behaviour:
The OpenWrite method opens a file if one already exists for the file
path, or creates a new file if one does not exist. For an existing
file, it does not append the new text to the existing text. Instead,
it overwrites the existing characters with the new characters. If you
overwrite a longer string (such as “This is a test of the OpenWrite
method”) with a shorter string (such as “Second run”), the file will
contain a mix of the strings (“Second runtest of the OpenWrite
method”).
So this is why you're getting a mangled file. You're overwriting the first N bytes with your updated key/value pairs, and the rest of the file is duplicated data from the original file. You probably want to use the following instead, which will overwrite the original file entirely:
using (StreamWriter sw = new StreamWriter(file, false))

Open file on combobox selection

I have a combobox which gets the list of items from the name of files I put together in one directory, the purpose for this is to make it dynamic - I'm very new to c# and it didn't occur to me a different way. - Here's the code for that bit:
string[] files = Directory.GetFiles(templatePath);
foreach (string file in files)
cbTemplates.Items.Add(System.IO.Path.GetFileNameWithoutExtension(file));
Basically, that works just fine, it populates my combobox with the names of the files I have in that path, the problem is that I need to open the file that's selected in the combobox and read its contents and place them in labels, I was thinking maybe StreamReader would help me here but I have NO clue on how to implement it, I've searched the internet but it looks like no one had the same idea before me. Can someone please point me in the right direction? A link to something similar or a guide of the objects I need to use would be great, thanks!
what you should do is store the names of the files in a single separate file (csv or xml). then use this file to both load the combobox and as an indexer.
for example lets say you have files a.txt, b.txt, and c.txt. you should (as you already are) read the file names programmatically THEN write them to a new file in whichever format you want, including a unique index scheme (numbers work fine).
your csv might look like this:
1, a.txt,
2, b.txt,
3, c.txt,
from here you can parse the newly created csv to your liking. Use it to populate your combobox, index being its value and filename its text. Then you can read your combobox selectedvalue, get the proper filename from the csv index, and finally open the file.
It may be longwinded but it'll work. You could also just use a multidimensional array, but this is more fun from an educational stand point, and it will help you with read/write operations.
It is not so easy to understand your problem. Do you want just to display filename w/o extension in your combobox? I hope this code will be usefull to you.
internal class FileDetail
{
public string Display { get; set; }
public string FullName { get; set; }
}
public partial class Example: Form // This is just widows form. InitializeComponent is implemented in separate file.
{
public Example()
{
InitializeComponent();
filesList.SelectionChangeCommitted += filesListSelectionChanged;
filesList.Click += filesListClick;
filesList.DisplayMember = "Display";
}
private void filesListClick(object sender, EventArgs e)
{
var dir = new DirectoryInfo(_baseDirectory);
filesList.Items.AddRange(
(from fi in dir.GetFiles()
select new FileDetail
{
Display = Path.GetFileNameWithoutExtension(fi.Name),
FullName = fi.FullName
}).ToArray()
);
}
private void filesListSelectionChanged(object sender, EventArgs e)
{
var text = File.ReadAllText(
(filesList.SelectedItem as FileDetail).FullName
);
fileContent.Text = text;
}
private static readonly string _baseDirectory = #"C:/Windows/System32/";
}
Thanks for all your help folks but I figured out how to get around my issue, I'll post the code for future incidents. pd. Sorry it took me this long to reply, I was on vacation
string[] fname = Directory.GetFiles(templatePath); // Gets all the file names from the path assigned to templatePath and assigns it to the string array fname
// Begin sorting through the file names assigned to the string array fname
foreach (string file in fname)
{
// Remove the extension from the file names and compare the list with the dropdown selected item
if (System.IO.Path.GetFileNameWithoutExtension(file) != cbTemplates.SelectedItem.ToString())
{
// StreamReader gets the contents from the found file and assigns them to the labels
using (var obj = new StreamReader(File.OpenRead(file)))
{
lbl1.Content = obj.ReadLine();
lbl2.Content = obj.ReadLine();
lbl3.Content = obj.ReadLine();
lbl4.Content = obj.ReadLine();
lbl5.Content = obj.ReadLine();
lbl6.Content = obj.ReadLine();
lbl7.Content = obj.ReadLine();
lbl8.Content = obj.ReadLine();
lbl9.Content = obj.ReadLine();
lbl10.Content = obj.ReadLine();
obj.Dispose();
}
}
}

Categories

Resources