First of all I would explain the situation.
I have a GUI which is stored on a server and should gain multiple user access. Users are working on different tabs (kind of separated workspaces).
Now when a user enters a tab it should be locked for other users (disabled).Other users should see if a tab is currently locked.
So my ideas on this are:
Create a textfile which lists the tabs and their current status (locked-unlocked).
A thread checks every few seconds if that file was modified. If yes then read it and disable or enable the corresponding tabs in the GUI.
3.When a user wants to enter a tab, check the file if the tab is unlocked (maybe a user was faster than the thread) and set it to locked.
When a user leaves a tab then set it to unlocked.
Now my questions are:
Is there a better or more efficient way to handle this situation?
And how to avoid the case that two users want to switch to the same tab at the same time, read that the tab is unlocked and write at the same time into the file?
Are there even more error cases?
Instead of a text file, you could use a proper SQL DBMS and transactions to keep the checking and updating atomic. It will cover all edge cases if you write your queries properly.
Something like:
begin tran
if not exists(select top 1 1 from tabs where id=#id and active=1)
begin
update tabs set active=1 where id=#id
select 1 --result
end
else
begin
select 0 --result
end
commit tran
Or even better, instead of just storing true/false to mean that the tab is in use, store a user identifier to know who's using it. That way if your application crashes/ends before releasing it, you can manually release it next time the same user logs in. You can also throw in an expiration date for the same purpose, and keep pushing it back while the application is online.
I understand from your question that you need to synchronize the applications running on different computers. You want to do it through a file located on a network drive, that is accessed from all of these computers, right?
Except shared file you can use IP/Ethernet broadcasting, or simple synchronizing server.
Among all these solutions the shared file is most simple, but no so effective.
Instead of it you can use similar technique with System.IO.FileSystemWatcher. In case of file watcher you'll create single file for each tab while it's locking; and delete it while tab is releasing.
File watcher frees you from having to re-read the content of the file, it raises an event instead when the file is changed.
This method would work with no so high load. If you're planning >50 users I think it's better to develop special server to synchronize users.
Short instructions:
Place FileSystemWatcher control on a form.
Setup property Path to desired network path (it's better to use new empty directory).
Create handlers for event Create and Delete:
void fileSystemWatcher1_Created(object sender, FileSystemEventArgs e)
{
var tabName = Path.GetFileName(e.FullPath);
var tab = tabControl1.TabPages[tabName];
// Do not disable selected tab cause you're working with the tab
// and you're locking it
if (tab != tabControl1.SelectedTab)
tab.Enabled = false;
}
void fileSystemWatcher1_Deleted(object sender, FileSystemEventArgs e)
{
var tabName = Path.GetFileName(e.FullPath);
var tab = tabControl1.TabPages[tabName];
tab.Enabled = true;
}
When a tab gets focus, you should create empty file with the tab name in the network directory:
. . .
var path = fileSystemWatcher1.Path;
var filename = Path.Combine(path, tabControl1.SelectedTag.Name);
using (File.Create(filename));
When a tab losts focus: you should delete file:
var path = fileSystemWatcher1.Path;
var filename = Path.Combine(path, tabControl1.SelectedTag.Name);
File.Delete(filename);
I feel xml file will be better than text file for this. As specified in the question you need to maintain status of each tab in the xml file indicating whether it is locked. you can handle selecting event of the tab control in which the type parameter e is TabControlCancelEventArgs and has the property Cancel by setting which to true will cancel selecting that tab. within this event you can check the xml file to verify that the tab is locked or unlocked and if locked, you can set e.Cancel=true and give a message to the user that this tab is locked.
you can use deselecting event of the tab control to know when a user moves out of that tab and update the status of that tab in xml file to unlocked.
Related
I'm creating app which is half-automated (user is opening tabs (attention) and if he wants to dump one of them he just clicks hot-key).
But when user opens to much tabs, I need to know to which one I should switch.
How can i get currenttab index. Or switch to current tab on Selenium C#?
string windowHandle = Browser.WindowHandles.Last();
string windowHandle = Browser.WindowHandles.First();
string windowHandle = Browser.WindowHandles[1];
...
is not working for me.
The currenttab index may get changed everytime you invoke Browser.WindowHandles().
Though the general perception is WindowHandles would be sorted like the oldest windows first and the newest windows last. But this is not the case: It is totaly random !
In a discussion, Simon clearly mentioned:
While the datatype used for storing the list of handles may be ordered by insertion, the order in which the WebDriver implementation iterates over the window handles to insert them has no requirement to be stable. The ordering is arbitrary.
This comment is pretty much inline with the Get Window Handles section where it mentioned:
In order to determine whether or not a particular interaction with the browser opens a new window, one can obtain the set of window handles before the interaction is performed and compare it with the set after the action is performed.
You can find a relevant detailed discussion in Best way to keep track and iterate through tabs and windows using WindowHandles using Selenium
Update
As per your comment user switch tab (in window) but driver is still focused on another tab you need to induce WebDriverWait for numberOfWindowsToBe(n) and you can find a detailed discussion in getWindowHandles() not working in firefox 58.The focus remains on parent tab and does not transfer to next tab
I know there is already a post with the same name as this but it provides a partial solution for the problem. The post is: VSTO Word post save event
I'm using this class and it helped me a lot. However, when I make changes in the Word file and try to Close the application clicking in the option "Not Save" the event of save is raised.
How can I know if the user has clicked in the "Save" or "Not Save" buttom when trying to close the window? I've tried everything but I can't know this information.
A quick test in VBA makes me believe this approach would be promising. DocumentBeforeClose is triggered before DocumentBeforeSave.
Declare a class-level field (saveStatus in the below code snippet).
In DocumentBeforeClose set it to "False" on the assumption the user won't save. If the user does save, set the value to True in DocumentBeforeSave. If you need to do something with the document when it's saved, put that code in this event, as well.
Private saveStatus as Boolean
Private Sub app_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean)
saveStatus = False
Debug.Print saveStatus
End Sub
Private Sub app_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
saveStatus = True
Debug.Print saveStatus
End Sub
For those facing the same problem I found a solution. Before I open the file in Word I read all bytes and store in a class variable, for example, wordContent using
wordContent = System.IO.File.ReadAllBytes(path);
Then, every time that I save without closing the application (i.e clicking in the save buttom in Word) I update this variable wordContent.
So, when I close the application and the event AfterSave is fired with my variable isClosed == true, in this point I don't know if the user closed the application clicking in Save or Not Save. So, I read the bytes of the word File and compare with my wordContent. When the user has clicked in the "Save" option the contents will be different, and when the user has clicked in the "Not Save" options the contents will be equal.
So, whatever it needs to be done it'll be in the comparison of this two byte arrays.
Remembering that I'm using the WordSaveHandler provided by the post that I pointed in the question above, this class can handle if the users save by clicking in the Save Buttom or by closing the application.
How do I create a resource that I can reference and use in various parts of my program easily?
My specific problem is that I have a NotifyIcon that I want to change the icon of depending on the state of the program. A common problem, but one I've been struggling with for a long time.
Well, after searching around and cobbling together various points from around StackOverflow (gee, I love this place already), most of the problems were already past this stage. I did manage to work out an answer to my problem though.
How to create a resource:
In my case, I want to create an icon. It's a similar process, no matter what type of data you want to add as a resource though.
Right click the project you want to add a resource to. Do this in the Solution Explorer. Select the "Properties" option from the list.
Click the "Resources" tab.
The first button along the top of the bar will let you select the type of resource you want to add. It should start on string. We want to add an icon, so click on it and select "Icons" from the list of options.
Next, move to the second button, "Add Resource". You can either add a new resource, or if you already have an icon already made, you can add that too. Follow the prompts for whichever option you choose.
At this point, you can double click the newly added resource to edit it. Note, resources also show up in the Solution Explorer, and double clicking there is just as effective.
How to use a resource:
Great, so we have our new resource and we're itching to have those lovely changing icons... How do we do that? Well, lucky us, C# makes this exceedingly easy.
There is a static class called Properties.Resources that gives you access to all your resources, so my code ended up being as simple as:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
Done! Finished! Everything is simple when you know how, isn't it?
The above didn't actually work for me as I had expected with Visual Studio 2010. It wouldn't let me access Properties.Resources, said it was inaccessible due to permission issues. I ultimately had to change the Persistence settings in the properties of the resource and then I found how to access it via the Resources.Designer.cs file, where it had an automatic getter that let me access the icon, via MyNamespace.Properties.Resources.NameFromAddingTheResource. That returns an object of type Icon, ready to just use.
The above method works well.
Another method (I am assuming web here) is to create your page. Add controls to the page. Then while in design mode go to: Tools > Generate Local Resource. A resource file will automatically appear in the solution with all the controls in the page mapped in the resource file.
To create resources for other languages, append the 4 character language to the end of the file name, before the extension (Account.aspx.en-US.resx, Account.aspx.es-ES.resx...etc).
To retrieve specific entries in the code-behind, simply call this method: GetLocalResourceObject([resource entry key/name]).
Code posted by Matthew Scharley has a memory leak:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
You should Dispose() notifyIcon.Icon before replacing it, because Properties.Resources.SOME_ICON creates a new Icon each time it is used.
This can be observed in the log, with this code:
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
You will see 3 different Hash Codes in the log. This means these are different Objects.
So, the simple fix will be:
paused = !paused;
notifyIcon.Icon?.Dispose();
notifyIcon.Icon = paused
? Properties.Resources.RedIcon;
: Properties.Resources.GreenIcon;
I have a c# method that needs to create two documents separately using PDF995. The simplified version:
public void PrintDocuments(PrintDocument report1, PrintDocument report2) {
PrintUtility.SetPDF995Key(); // Method to set the product code in the registry.
report1.Print(); // PDF995 "Save as" dialog box appears here.
PrintUtility.SetPDF995Key();
report2.Print();
}
In order to create a document and avoid having all the PDF995 advertising banners appear, I first have to set the Product Code as a Registry item. However as soon as you click on Save in the PDF995 Save File Dialog, the product key is blanked out, which means I would have to set the Product Code again to create the second document.
The problem is, the Save File dialog box is displayed as an asynchronous / modeless dialog box, which means that the code which creates the second document is reached before the user has had a chance to click on Save for the first one.
So now, even though the Product Code is set a second time, clicking on Save for the first document will blank it out, and because the program has already passed the call to the PrintUtility.SetPDF995Key() method before printing the second one, it will still be blank when the second Save File Dialog appears and so I get the annoying "Trial version" banners.
So is there any way around this? e.g. is there a way to make the Save As dialog Modal, or an event when "Save" is clicked that can be fired so I can call PrintUtility.SetPDF995Key() immediately, or some way of permanently setting the Product Code or something else?
I have several checkboxes within ToolStripMenuItem within a window form.
I need to setup the registry (I think this automatic when saving, correct?)
I need to save the checkboxes into registry (during form.closing event)
I need to load the registry and set the checkboxes when form is loaded.
I would like an option to save it to files (save and load) as well.
I read about ConfigurationManager but it look rather complicated (from MSDN source), it this the best solution?. Is there link to simple demo program that done this (to file rather than registry).
Yes, you really ought to use a Setting. Project + Properties, Settings tab. Add one: Name = Option1Checked, Type = bool, Scope = user, Value = false.
In your form's Load event, you'd write:
option1ToolStripMenuItem.Checked = Properties.Settings.Default.Option1Checked;
And in the FormClosing event, you'd write:
Properties.Settings.Default.Option1Checked = option1ToolStripMenuItem.Checked;
Properties.Settings.Default.Save();