I have been working with a simple program essentially designed to be digital flash cards. Ideally, I want the program to be portable. I am trying to get the current directory. My setup is this:
I have a FileIO.cs method which reads currentDir/Data. I then have a winform which calls the method and retrieves a string[] array of the list of folders. Both of these methods are public static. I then have a separate button to create controls on the form.
The problem:
I have cleaned/rebuilt the solution and been using the debugger; The program is running from C:\Users\user\a\b\c\solution\bin\debug. The control (radioButton) I created to verify this data is telling me the 'currentDir' is C:\Users\user and not the programs current directory.
Notes:
I have manually created Debug\Data and 4 folders within the data folder so I am 100% sure they exist. No warnings or compile or run time errors are thrown. Card_Base.GetGrades is automatically called on form load successfully.
I have also confirmed the Release folder is empty and not being used. Also I have a backup program which shows an icon when a file is being uploaded to my backup every time the file(s) change. So I am 100% sure bin\debug is the proper working folder in this scenario.
Perhaps what is puzzling me most is that I have a totally separate program written on the same PC using the same IDE and it properly retrieves the path using the same setup.
In FileIO.cs
//public static string pathPortable = System.IO.Directory.GetCurrentDirectory();
public static string pathPortable = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
static string[] grade1;
public static string[] GetGrade()
{
string fullPath = FileIO.pathPortable + #"\Data";
grade1 = Directory.GetDirectories(fullPath);
return grade1;
}
in Card_Base.cs
public static List<RadioButton> buttonGrade = new List<RadioButton>(10);
public static void GetGrades()
{
string[] grade2 = FileIO.GetGrade();
//Proper and accurate names of the folders I manually added
//C:\Users\user\a\b\c\solution\bin\debug\Data\K
//C:\Users\user\a\b\c\solution\bin\debug\Data\1
//C:\Users\user\a\b\c\solution\bin\debug\Data\2
//C:\Users\user\a\b\c\solution\bin\debug\Data\3
MessageBox.Show("" + grade2[0]); //Information (entire path) is accurate as of this line
int x = 5;
int y = 0;
for (int i = 0; i < grade2.Count(); i++)
{
y = i * 21;
Card_Base.buttonGrade.Add(new RadioButton());
Card_Base.buttonGrade[i].Text = grade2[i];
MessageBox.Show("" + buttonGrade[i].Text); //Proper entire path is shown here!
Card_Base.buttonGrade[i].Location = new System.Drawing.Point(x, y);
}
}
The control whose .text property which shows C:\Users\User, not the Bin\Debug folder.
private void buttonTest_Click(object sender, EventArgs e)
{
MessageBox.Show("abc:" + buttonGrade[0].Text);
for (int i = 0; i < buttonGrade.Count(); i++)
{
panelGrade.Controls.Add(buttonGrade[i]);
}
MessageBox.Show("def:" + buttonGrade[0].Text); //Proper string path is displayed in the popup box here!
}
Result: ???
Four vertically lined radioButtons on a form panel which all have text reading "C:\Users\user\"
Update1:
The text also appears slightly misaligned, slightly higher than the radioButton bubble itself, very strange. However, I've gone back into the editor and confirmed the panelGrade is initially empty. Click/Drag grabs nothing and right clicking the panel does not reveal any underlying objects in the panel's space.
After modifying the target directory to its parent (1 level higher), each messageBox checkpoint reveals the proper string/path is being sent in. The visible radioButton when the program is launcher, after the "test" button is pushed is the only occurrence of this unusual text/string appearing anywhere.
Placing messageBoxes before/after the loop within the test button itself shows that the control (radioButton in buttonGrade[0]) DOES contain the proper string / text / path. Thus the change must occur at some point after the buttonTest code is finished executing.
Update2:
I just opened a brand new solution and copy/pasted the relevant code eliminating anything extraneous. Named all the items/controls with the same names. Completely bare bones. Exact same problem.
HOWEVER, when I change radioButtons to TextBoxs ... the program displays the proper information. Um. What???
Update 3:
Looking through the MSDN radioButtons are derived from buttonBase. The only relevant event I see at a glance is the textChanged event. While it does note that the way the text property of derived classes like radioButton varies, it fails to specify exactly how or what limits it has. Control.Text is simply a System.String , thus I see no reason why a radioButton would not be able to contain that information.
I tried creating a 'test2' button to change 'buttonGrade[0].Text = FileIO.pathPortable;' . Oddly enough, it does not change the text all. Nor does it throw an error.
AH HA! I noticed that the folder after user was my google drive, which is "Google Drive" and has a space in it. I then copied my trash program to C:\and named it TrashMe2 and ensured no folder names contained spaces. The result was "C:\TrashMe2\bi". I then tried "1234567890123456789". The result was that it showed up to the second 3.
The radioButton wasn't receiving a different string and the string/path/data was never changed. It simply showed a 'different folder' because that, by luck of the draw' was the exact number of visible characters it showed. Because I created the radioButtons programmatically, AutoSize did NOT default to true. The proper string was part of the radioButton, it simply was not all visible.
And for security reasons (and a bit of humor), I actually call my user account "user". So it wasn't a scenario where I would see C:\Users\JoeNomidBlow was cut off.
I feel... rather stupid at this particular moment. Thanks for the help!
Programmatically adding a control, particularly a radioButton, does not automatically set the autoSize property to true. When creating a radioButton programatically, one must be sure to add
radioButton.Autosize = true;
or as this case is/was
buttonGrade[i].Autosize = true;
Otherwise the visible space of the text is shortened. In this case, leaving behind a partial path. Which coincidentally happens to be identical to a different valid path.
Related
I am trying to make my app stay the way I left it after closing the app. Therefore I want to save set of items from ListView to the settings and I can't figure out how to do that. I've found some solutions but I believe they are outdated as they don't seem to work.
Image shows set of items in ListView which I want to save so they appear there after restarting the app:
Items
This is where I want them to appear:
Settings
And this is part of code that I've tried out so far
private void btn_SaveConfig_Click(object sender, EventArgs e)
{
int i = 0;
Settings.Default["IP"] = tBox_discoverServerFrom.Text;
Settings.Default["DiscoveredServers"] = cBox_discoveredServers.Text;
foreach (var item in lV_groups.Items)
{
var property = new System.Configuration.SettingsProperty("Group"+i);
property.PropertyType = typeof(string);
property.Name = "Group " + i;
Settings.Default.Properties.Add(property);
Settings.Default.Save();
i++;
}
}
I do not think using the Settings API is a great idea if you want to save any significant amount of data.
I would recommend the following
Create a class describing all the data you want to save. To make serialization easier it should have a parameter less constructor and public setters for all properties. This is sometimes called a Data-Transfer-Object (DTO)
Use json to serialize the object to a file. You would normally place the file in a subfolder in the local app data folder: Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).
Do the reverse when you start the application. If there is a file, use Json to deserialize it and use it however you want.
You may optionally add logic to save the file periodically, this would allow recovery in case of application crashes. You might also want some system to keep more than one file, in case the application or computer crashes in the middle of a save operation, and the file becomes corrupt.
First of all I am a newbie in C# Programming, and I need to create a simple MRU as fast as i could.
Well the thing is I've tried looking at some online examples but however I found them to be quite a bit too confusing...
So is there anyway that anyone can create a "Recently Used" section in the toolstripmenuitem without going into those complicated codes??
E.g I will not be able to understand this stuff...
Registry key:
KEY_CURRENT_USER\Software\Microsoft\VCExpress\9.0\FileMRUList
Code:
Application.UserAppDataRegistry.DeleteSubKey("MRU", false);
RegistryKey appKey = Application.UserAppDataRegistry.CreateSubKey("MRU");
dictionary
microsoft.win32
I will only need something as simple as shown in this link below http://www.codeproject.com/KB/menus/MRUHandler.aspx
So you want to create a submenu like in the screenshot? For this, you will have to:
Store the list of recently-used files somewhere. This could be the registry, or it could just be a simple textfile, which I’ll do now to keep it simple.
Learn how to generate menu items at runtime instead of in the designer.
1. Store the MRU in a file
You will probably have already declared a private field to contain your MRU, right?
private List<string> _mru = new List<string>();
Every time someone opens a file, you add this file to the beginning of the MRU, right?
_mru.Insert(0, fullFilePath);
Now, of course when the application closes, you need to save this MRU to a file. Let’s do that in the Form’s FormClosed event. Double-click the FormClosed event in the properties and write some code which looks somewhat like this:
var appDataPath = Application.UserAppDataPath;
var myAppDataPath = Path.Combine(appDataPath, "MyApplication");
var mruFilePath = Path.Combine(myAppDataPath, "MRU.txt");
File.WriteAllLines(mruFilePath, _mru);
Now we have saved the MRU in a file. Now obviously when the application starts, we need to load it again, so do something like this in the form’s Load event:
var appDataPath = Application.UserAppDataPath;
var myAppDataPath = Path.Combine(appDataPath, "MyApplication");
var mruFilePath = Path.Combine(myAppDataPath, "MRU.txt");
if (File.Exists(mruFilePath))
_mru.AddRange(File.ReadAllLines(mruFilePath));
2. Create the menu items
Now that _mru contains the file paths that we want in our menu, we need to create a new menu item for each. I’ll be assuming here that you already have a menu item in the File menu (the item called “Most Recently Used” in your screenshot) and that it is called mnuRecentlyUsed, and that we only need to create sub-items:
foreach (var path in _mru)
{
var item = new ToolStripMenuItem(path);
item.Tag = path;
item.Click += OpenRecentFile;
mnuRecentlyUsed.DropDownItems.Add(item);
}
Now all we need is the method that actually opens a file, which I called OpenRecentFile:
void OpenRecentFile(object sender, EventArgs e)
{
var menuItem = (ToolStripMenuItem) sender;
var filepath = (string) menuItem.Tag;
// Proceed to open the file
// ...
}
Disclaimer
Please don’t use any of this code unless you understand it and you are sure that it is written to do what you intended. If it needs to do something slightly different, I’m sure you can make the necessary changes yourself.
Also, I’m sure you will have noticed that the above doesn’t update the sub-menu while the program is running. If you understand how the above code works, then I’m sure you’ll be able to figure out the rest for yourself.
http://www.codeproject.com/Tips/680088/Recent-Items-Tool-Strip-Menu-Item
This project does exactly what you want
I am using the JitBit Macro Recorder to create "bots" that save me a lot of time at work. This program can use the mouse and the keyboard and perform tasks by checking different if-options like "if image found on screen".
My newest "bot" is about 900 lines of commands long and I would like to make a log-file to find an error somewhere in there. Sadly, this program doesn't offer such an option, but it let's me use c# as a task. I have NO experience with c# but I thought, that this is easy to do for someone who has some experience.
If I click execute c# code, I get the following input field:
Important: This code MUST contain a class named "Program" with a static method "Main"!
public class Program
{
public static void Main()
{
System.Windows.Forms.MessageBox.Show("test");
}
}
Now I need two code templates:
1. Write a message to a "bot_log.txt" located on my desktop.
[19.05.2016 - 12:21:09] "Checking if item with number 3 exists..."
The number "3" changes with every run and is an exact paste of the clipboard.
2. Add an empty line to the same file
(Everything should be added to a new line at the end of this file.)
If you have no idea how to program in C#, then you should learn it,
if you want to use code provided from answers.
And if you want to generate timestamps and stuff then it's not done within minutes and I don't think someone writes the whole code just for your fitting. Normally questions should have at least a bit of general interest.
Anyway:
This works, if you have a RichTextTbox in your program.
Just do a new event (like clicking a button) and do this inside it.
(This was posted somewhere here too or on another site, with sligh changes)
public static void SaveMyFile(RichTextBox rtb)
{
// Create a SaveFileDialog to request a path and file name to save to.
SaveFileDialog saveLog = new SaveFileDialog();
// Initialize the SaveFileDialog to specify the RTF extention for the file.
saveLog.DefaultExt = "*.rtf";
saveLog.Filter = "RTF Files|*.rtf"; //You can do other extensions here.
// Determine whether the user selected a file name from the saveFileDialog.
if (saveLog.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
saveLog.FileName.Length > 0)
{
// Save the contents of the RichTextBox into the file.
try
{
rtb.SaveFile(saveLog.FileName);
}
catch
{
MessageBox.Show("Error creating the file.\n Is the name correct and is enough free space on your disk\n ?");
}
MessageBox.Show("Logfile was saved successful.");
}
}
I am having trouble copying cells from a WPF datagrid. I have a few other text editor windows (like Avalonedit) in the same app from where I can copy to Clipboard but not from the datagrid. Whenever, I try to copy even one cell I get the message "Open Clipboard Failed (Exception from HRESULT: 0x800401D0).
So I can copy paste everything else except from the datagrid. I tried the OpenClipboard and CloseClipboard approach but that didn't seem to work for me either.
I have looked at the approach mentioned here. (http://blog.somewhatabstract.com/2012/06/27/when-the-clipboard-says-no/) but I am unable to find out how to override the method OnExecutingCopy unless I derive from a DataGrid and do something.
#ssarangi
Hi ssarangi...I don't know if you ever solved this clipboard issue, but I encountered your question while trying to find a solution to a clipboard-contention problem some of my users are having intermittently. What I'm doing is a two-pronged approach:
Switched to using System.Windows.Forms.Clipboard.SetDataObject("string", false, retryTimes, retryDelay)
Added logic to find the app with which I'm having the contention.
I answered another, similar question in which I included the code snippet, so if you're still looking for some assistance you can check it out and see if it helps: OpenClipboard Failed when copy pasting data from wpf DataGrid
In essence I used two DllImport's for GetOpenClipboardWindow() and GetWindowThreadProcessId(), and then I get all the active Process objects via Process.GetProcesses() and iterate through them looking for a match on either the window handle from GetOpenClipboardWindow() or a match on Process.Id (the PID) I obtained via GetWindowThreadProcessId(). This isn't a solution, but it might help identify what is locking you out of the clipboard.
The other thing I'm doing which again might help is switching to the System.Windows.Forms Clipboard class with the built-in retry loop for SetDataObject().
I know this is an older post, but this solution is posted for completeness and is missing the use of a suited DataGrid event method signature associated with the DataGridRowClipboardEventArgs.
Clipboard.SetText can be flaky, not grabbing/setting the clipboard all the time.
Set "FullRow" at the SelectionUnit mode for dataGrid called myDataGrid
<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>
We have a method myDataGrid_CopyingRowClipboardContent that gets called for each row in the dataGrid to copy its contents to the clipboard. For example,for a datagrid with 7 rows this is called 7 times.
public int clipboardcalledcnt { get; set; } //CopyingRowClipboardContent invoked count
private void myDataGrid_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
PathInfo cellpath = new PathInfo(); //a custom class to hold path info
string path = string.Empty;
DataGrid dgdataPaths = (DataGrid)sender;
int rowcnt = dgdataPaths.SelectedItems.Count;
cellpath = (PathInfo)e.Item;
path = "Row #"+ clipboardcalledcnt +" Len="+ cellpath.Length.ToString() + ", path=" + cellpath.Path;
e.ClipboardRowContent.Clear();
if (clipboardcalledcnt == 0) //add header to clipboard paste
e.ClipboardRowContent.Add(new DataGridClipboardCellContent("", null, "--- Clipboard Paste ---\t\t\n")); // \t cell divider, repeat (number of cells - 1)
clipboardcalledcnt++;
e.ClipboardRowContent.Add(new DataGridClipboardCellContent(path, null, path));
if (clipboardcalledcnt == rowcnt)
clipboardcalledcnt = 0;
}
I see a lot of people coming up with some excessive ways to change the folder location on the fly with flajaxian multiple file upload control.
Was just wondering if the more experienced could take a look at the way I've come up with and let me know if there are any major issues I should be concerned about. (Assuming I have the proper error checking in place.)
I planned on initializing the control as seen below. :
<cc1:FileUploader ID="FileUploader1" runat="server" OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
</cc1:FileUploader>
(I RequestAsPostBack="true" as there are some other controls I need to check in my event handler)
I simply change the HttpFileCollection.SaveAs property in the fileUploader_FileReceived event. Since flajaxian does this one file upload at a time, we can expect that there is only 1 file in the collection (or else we could use a loop).
protected void fileUploader_FileReceived(object sender,
com.flajaxian.FileReceivedEventArgs e)
{
HttpFileCollection files = Request.Files;
// Change path to whichever folder I need
String TempFileName = "C:\\NEW\\PATH\\TO\\Folder\\" + files[0].FileName;
// Save the file.
files[0].SaveAs(TempFileName);
}
This implementation seems to work great as long as the folder is existing! I was just wondering if there is anything technically wrong with an implementation like this, again , assuming all error checking was in place.
Thanks!
A better way to do this would be to use an adapter, and over write the folder location in the
OnFileNameDetermining event. This way, we also get all the goodies with the adapter.
<cc1:FileUploader ID="FileUploader1" runat="server"` OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
<Adapters>
<cc1:FileSaverAdapter runat="server" FolderName="Ups" OnFileNameDetermining="fileUploader_FileDetermined" />
</Adapters>
</cc1:FileUploader>
In the file determined event, we can change the folder location programatically
protected void fileUploader_FileDetermined(object sender, com.flajaxian.FileNameDeterminingEventArgs e)
{
e.FileName = "C:\\NewFolder\\" + e.File.FileName;
}
We can use the FileReceived event to check if the folder exists, and if not, create it.
protected void fileUploader_FileReceived(object sender, com.flajaxian.FileReceivedEventArgs e)
{
int fileIndex = e.Index;
if (fileIndex == 0)
{
// We are on our first file, check if the new folder exists, if not, create it
}
}
What you are doing is fine, although, if you are saving files within the web site, consider using the MapPath method to create a physical folder from a virtual path within the web site
MapPath("/Images/User1")
This my mininal APSX implementation
<fjx:FileUploader ID="FileUploader1" runat="server" OnFileReceived="FileUploader2_FileReceived">
</fjx:FileUploader>
No adapters or folder is specified. When the FileRecevied event fires, I save files to a folder based on the Forms Authentication user name (names do not use characters not allowed in folder names).
Also note that the FileReceivedEventArgs has a reference to the (HTTP) file
e.File
The FileUploader control will show all files processed - you can even set the status code (e.g. 550) if there is an error, which is returned to the client.
Note that, the server call to the FileReceived event does not occur inside a nornal page postback, even if you specify
RequestAsPostBack="true"
So, a PagePreRender does not take place.
The only issue is, how do you perform any other processing at the client after the uploads complete (e.g. showing images uploaded).
Work I have in progress to this end is to use the client side event
FileStateChanged
When the last file is processed
if (file.state > Flajaxian.File_Uploading && isLast) {
I use JQuery to click a hidden submit button. The postback looks through session values stored when the files were saved, and renders back the images into a DIV.
However, an immediate submit causes issues with empty session inside the FileReceived event for some reason (I assume because the internal asynchronous call back has not completed). A pause of a few seconds before initiating the postback works OK.