I need to Enable/Disable my SAVE button in real time based on data in my fields.
Is the below an acceptable way on accomplishing this? It feels wrong but I don't know how else I could accomplish this.
Each User Control(CRUD Form) has a BackgroundWorker and the following related methods;
StartBGWorker()
StopBGWorker()
RequiredFieldsValid()
There purpose is self-explanatory, I hope. The process goes in such a way that when a User clicks NEW or EDIT it places a call to StartBGWorker() which creates a new BackgroundWorker and calls RunDataASync() for it. The DoWork() method of the BGWorker looks like this:
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ucNavDiagnosis.btnSave.Enabled = Convert.ToBoolean(e.UserState);
}
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
bgWorker.ReportProgress(0, RequiredFieldsValid());
System.Threading.Thread.Sleep(500);
}
}
private bool RequiredFieldsValid()
{
// TODO: Add other required fields
return (!memAllergies.Text.Equals(string.Empty));
}
This works but feels "bush-league." Anyway, when the User clicks SAVE or CANCEL a call to StopBGWorker() is placed which Disposes the worker.
As a further disclaimer, this app does not currently use binding. It's a long explanation but that's that, as they say.
How about using the validating events to update the enabled status of your save button?!!
protected virtual void MyTextBox_OnValidating(CancelEventArgs e)
{
this.SaveButton.Enabled = (Validate(MyTextBox));
}
As well, if you are doing validation, I highly recommend looking into MS enterprise library validation to handle informing the user of input errors. Also, check out this.
Related
In the documentation of the Siemens TIA-Portal Openness API you can read the following:
There is an event, when a confirmation box opens, and an event when the confirmation is given by the user.
//Register event handler for Notification-Event
....
tiaPortal.Notification += TiaPortal_Notification;
....
private static void TiaPortal_Notification(object sender, NotificationEventArgs e)
{
....
}
//Register event handler for Confirmation-Event
....
tiaPortal.Confirmation += TiaPortal_Confirmation;
....
private static void TiaPortal_Confirmation(object sender, ConfirmationEventArgs e)
{
....
}
The documentation gives this much information on reacting to the events
I want to react on the notification event. But the NotificationEventArgs Class does not contain an result attribute which i can write on, and does not contain any method of some kind to send a confirmation. There is only one writeable attribute, called IsHandled. But nothing happens if i write to that, so i suggest this is only an internal confirmation
My understanding of the api documentation ist, that it is something native of c#/.net? maybe a function of some kind, to raise reactions on events?
This answer is valid for TIA 16 with Openness API V16.
Confirmations: If a prompt is triggered in TIA Portal that requires a user decision (i.e. has more than one button), ConfirmationEvent is raised, and it definitely happens prior to any decision being made by the user.
Set IsHandled, then set the Result value. That's all you need to do.
private static void Tiap_Confirmation(object sender, ConfirmationEventArgs e)
{
//signal to TIA Portal that the event is handled
e.IsHandled = true;
//handle the various events
if (CONDITIONS_FOR_CHOOSING_YES)
e.Result = ConfirmationResult.Yes;
if (CONDITIONS_FOR_CHOOSING_CANCEL)
e.Result = ConfirmationResult.Cancel;
...
}
Notifications: NotificationEvent is only raised for prompts that have one button. The example below is for a .NET Framework console application.
using Siemens.Engineering;
using System;
using System.Linq;
using System.Threading;
namespace OpennessConsoleTests
{
class Program
{
static void Main(string[] args)
{
//attach to the first tia portal process found
TiaPortal tiap = TiaPortal.GetProcesses().First().Attach();
//subscribe to confirmation event
tiap.Notification += Tiap_Notification;
//pause
Console.WriteLine("Waiting for events. Press Ctrl+C to quit");
//sleep indefinitely. User must ctrl+C out of this
Thread.Sleep(Timeout.Infinite);
}
private static void Tiap_Notification(object sender, NotificationEventArgs e)
{
e.IsHandled = true;
Console.WriteLine("*****Notification*****");
Console.WriteLine("Caption: " + e.Caption);
Console.WriteLine("Text: " + e.Text);
Console.WriteLine("DetailText: " + e.DetailText);
}
}
}
An important note: According to my testing, some prompts do not raise an event even if subscribed, for example "Subfolder already exists" when extracting an archive. This puts TIA Portal into a locked state until you stop your application.
I think it's just a (not optimal) translation into German. What they mean is you need to set a field in the event args you got. This is a normal pattern in .NET.
Something like this (don't have the library for syntax check but you should get what I mean):
private static void TiaPortal_Confirmation(object sender, ConfirmationEventArgs e)
{
// do your thing, open a confirmation dialog or something, then:
e.Result = Choices.OK;
}
Background: I'm creating an app that allows our other techs to quickly install a dozen or so programs within one simple GUI. I am embedding the installers of those apps within my main program. (not that it matters)
I created a separate class file (IsOfficeInstalled.cs) that gets called when a user clicks on a button to install Office. Here's the code in that file:
class IsOfficeInstalled
{
public static bool check()
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Winword.exe");
if (key != null)
{
key.Close();
}
return key != null; }}
In my MainWindow.xaml file, I am trying to call the "IsOfficeInstalled" function and perform one of two actions based on the return value. This is where I am confused. The code in my button event looks like the following:
private void btn_InstallOffice_Click(object sender, RoutedEventArgs e)
if (IsOfficeInstalled.check())
{
//If yes, then perform some code
}
else
{
//If no, then perform some different code
}
Where I need help is, getting the true/false result back from the "IsOfficeInstalled" function so my code in the "btn_InstallOffice_Click" function will know which condition to execute.
I'm not sure if I'm understanding your question. Are you looking for a simple if statement?
private void btn_InstallOffice_Click(object sender, RoutedEventArgs e)
{
if (IsOfficeInstalled.check())
{
//If yes, then perform some code
}
else
{
//If no, then perform some different code
}
}
I'm C# with Compact Framework and I realized something weird today. I'm calling a method by an event that applies a set to an object and when I debug, it passes by this, but just performs after the last close bracket of the method. My example:
public string Loading
{
set { lblLoading.Text = value; }
}
private void btnAuth_Click(object sender, EventArgs e)
{
Loading = "Loading...";
_presenter.PerformAuth();
}
When I debug, it passes by my first statement, applies it, but doesn't change anything on the screen... Oh, until it do PerformAuth(). After it, so, then the label value is changed. Oh, the problem isn't just by it be synchronous. The same occurs when I try to do an asynchronous task:
private void btnAuth_Click(object sender, EventArgs e)
{
ASyncResult res = BeginInvoke(new Action(() =>Loading = "Loading..."));
EndInvoke(res);
_presenter.PerformAuth();
}
I think it might be a bug in thread and in C# design implementation. And also with direct set it is stubborn to me. As you can see in the image below:
I just want to set a text in a label, call a method and unset it in an event. Why does C# get it so complicated?
I have an API (dll) that collects stock ticks via an event mechanism. Such as below:
...
using MT4API;
public partial class Blue : Form
{
...
public Blue()
{
...
string symbol = "GBPUSD";
MT4DDE dde = new MT4DDE("");
dde.OnQuote += new System.EventHandler<QuoteEventArgs>(MT_OnQuote);
dde.Connect();
dde.Subscribe(symbol);
....
The idea is that on each chart tick I get an event. here is the event handler code:
private static void MT_OnQuote(object sender, QuoteEventArgs args)
{
GlobalClass.Ask = args.Ask;
GlobalClass.Bid = args.Bid;
// I have back ground worker code that updatestables from the global class
}
This all works fine. So long as I do not touch any other buttons on the form UI. As soon as I click a button on the form of the UI... I no longer receive events from my API, the UI application functions normally, but with no data from the API.
Why do events from the UI stop any further events coming from the API event?
Any idea whats going on here? Or suggestions how to design this?
Does the same problem occur if you comment out your code that updates the tables from the global object? and if you comment out the background worker?
It would be a good idea to distinguish if the event stops being fired just after you press some button on the UI, or if it stops being fired only after some line of code you wrote is being executed.
In order to be able to help you, we would need to know how the event on the MT4DDE class is triggered.
If you have the code for this class, posting it would help.
If you don't you may want to use a tool such as Reflector to decompile the assembly into C# and see what the MT4DDE class is doing that might cause it to stop invoking the event.
In addition, if you are doing anything related to background threads, or if you're doing anything unusual with your application's main message loop, it would be a good idea to mention it here.
I have tried to use the invoke command, it works, but after a few events it stops...here is the code isolated:
using MT4API;
namespace WindowsFormsApplication1
{
public delegate void UpdateTextCallback(double ask, double bid);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string symbol = "GBPUSD";
MT4DDE dde = new MT4DDE("");
dde.OnQuote += new EventHandler<QuoteEventArgs>(MT_OnQuote);
dde.Connect();
dde.Subscribe(symbol);
}
private void updateTickDisplay(double ask, double bid)
{
textBox1.Text = ask.ToString();
textBox2.Text = bid.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void MT_OnQuote(object sender, QuoteEventArgs args)
{
BeginInvoke(new UpdateTextCallback(this.updateTickDisplay),
new object[] { args.Ask, args.Bid });
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox3.Text = textBox1.Text;
}
}
}
The only difference from the real code is that I am using a data grid....as opposed to a text field. But it is clear that the UI blocks somehow the new events. It is strange that I get about 5 to 10 events and then it just stops. Strange. Any ideas on a differnet design?
I have an autocompleate textbox that looks into a data base. Some times while I'm typing I received the following error.
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Here is the code
private void tBSearchName_TextChanged(object sender, EventArgs e)
{
try
{
//test length
if (tBSearchName.Text.Length > 3)
{
//prevent db lookups
if (!tBSearchName.Text.ToLower().Contains(oldName) || oldName == String.Empty)
{
//test for a name + first letter of last name
if (Regex.IsMatch(tBSearchName.Text, #"(\w)+\s(\w)+(\.)*"))
{
tBSearchName.AutoCompleteCustomSource = AccessDB.serachByNemberName(tBSearchName.Text);
tBSearchName.AutoCompleteMode = AutoCompleteMode.Suggest;
//prevent db lookups
oldName = tBSearchName.Text.ToLower();
}
}
}
}
catch
{
}
}
My insight is that I should frezz typing into the application while search is done, can some suggest how to do this. Or any other insight on what is happening
It is a bug in Windows Forms's wrapper of autocomplete APIs. Windows Forms does not protect the AutoCompleteCustomSource object from being replaced while it is being enumerated by a background thread created by autocomplete.
Instead of replacing the data store, you can try replace the autocomplete object or use the IAutoCompleteDropDown interface to reset the enumerator.
You can use lock:
private void tBSearchName_TextChanged(object sender, EventArgs e)
{
lock(this) { /* do magic */
}
Do note that it's bad practice to perform long tasks in the event handlers. If the search takes more then 30ms, better use a worker thread.