I just need to create a function to checkbox that will return the current value of checkbox.
I wrote :
private void Checkbox_check()
{
if (checkBox1.InvokeRequired)
return (int)checkBox1.Invoke(new Func<int>(checked));
else
return checkBox1.Checked; // bad here i know
}
What is bad here, can someone just write correctly this function? I need Invoke because can't use in another Thread without invoke. I just search a forum and web about help but can't find solution anywhere.
Don't use Func<> as it doesn't return anything. Use Action instead.
private void Checkbox_check()
{
if (checkBox1.InvokeRequired)
checkBox1.Invoke(new Action(Checkbox_check));
else
{
// do what you like to do on the ui context
// checkBox1.Checked; // bad here i know, yep...
}
}
Getting the checked state from another thread, you could do like this:
private bool Checkbox_check()
{
// result value.
bool result = false;
// define a function which assigns the checkbox checked state to the result
var checkCheckBox = new Action(() => result = checkBox1.Checked);
// check if it should be invoked.
if (checkBox1.InvokeRequired)
checkBox1.Invoke(checkCheckBox);
else
checkCheckBox();
// return the result.
return result;
}
I would not advise this, this could lead to deadlocks etc. I advise you to pass the checked value on the threadstart, so you don't have to do any crossthread calls.
You should write it this way:
private void Checkbox_check()
{
if (checkBox1.Invoke:DRequired)
return (int)checkBox1.Invoke(new Func<int>(checked));
else
return checkBox1.Checked.(initInvoke);
}
Related
I have a method that returns an ItemCollection, I want to stop the function early if there is no information provided. I would normally do this with a return; however as my method expects an ItemCollection it fails. I have this as a work around but it seems frankly hacky. Is there something I am missing. I tried just return; and I would prefer not throw an exception.
private ItemCollection loadLeft_Click(object sender, RoutedEventArgs e)
{
var leftUser = UsrLeft.Text;
if (leftUser == "")
{
MessageBox.Show("No User Entered");
GroupListLeft.Items.Add("");
var fail = GroupListLeft.Items;
return fail;
}
//Succesful test do stuff
var leftItems = GroupListLeft.Items;
return leftItems;
}
You have few options:
throw a new Exception (maybe even a custom one like NoUserEnteredException("someText")).
return null
return an empty collection or dummy object (see Null-object pattern)
The last one is better choice, in this case you don't need write a null-check or a try-catch section in client code.
You will need to return something that equates to an ItemCollection, depending on how you may want the calling procedures to handle such a return you could use a null return:
if (leftUser == "")
{
MessageBox.Show("No User Entered");
return null;
}
Or return a new ItemCollection e.g.
if (leftUser == "")
{
MessageBox.Show("No User Entered");
return new ItemCollection();
}
You will need to return null, like
private ItemCollection loadLeft_Click(object sender, RoutedEventArgs e)
{
var leftUser = UsrLeft.Text;
if (leftUser == "")
{
MessageBox.Show("No User Entered");
return null;
}
//Succesful test do stuff
var leftItems = GroupListLeft.Items;
return leftItems;
}
You can use "return null" which I do from time to time, but its not a good coding convention. Another option is to throw an exception and then catch it. Both is bad coding conventions and makes the code that uses this button add some rather obscure logic and dependencies.
From studying SOLID principles I would argue a better solution is to make a new type of object to return. f.ex. one that holds a list, but also a status message and then make it react a bit like when you have an HTTP request that depends on a success and otherwise cannot expect to have any content. This way, the object makes it clearer what to expect.
A fourth option, since this sounds UI related, is to possible have the click callback somehow and either update the collection, or update with an error message directly. But this might also be a bad coding convention that has impractical dependencies in the code.
Your code seems to return an object when you click on something.
(I am no expert in WPF, i don't know if this is possible).
I would encapsulate the function that returns the ItemCollection in a separate function and check whether the User is valid BEFORE calling this function.
This way you ensure that the ItemCollection is always valid (because you don't even try to retrieve it with an invalid user). Something like this:
private void loadLeft_Click(object sender, RoutedEventArgs e) {
var leftUser = UsrLeft.Text;
if(leftUser != "") {
ItemCollection coll = getItemCollectionForUser(leftUser);
}else {
//Error Handling
}
}
private ItemCollection getItemCollectionForUser(string user) {
//return ItemCollection here
}
Note how I wrote a separate function that returns the ItemCollection and the Click function returns nothing.
I'm currently implementing a MessageDialog control. It is there to replace MessageBox entirely and is displayed as an "in-window popup" (correct UX term needed).
Currently, its constructor is private and there is a method Show, just like in MessageBox.Show. However, MessageBox blocks the UI thread and returns a result.
What my MessageDialog control currently does is having a Action<MessageDialogResult> callback parameter which gets called when a button is clicked.
Utilizing MessageDialog
// class MessageDialog
public static void MessageDialog.Confirmation(Window owner, string message, Action<MessageDialogResult> callback);
// When used by other controls
MessageDialog.Confirmation(WindowMain.Singleton, true, (result) =>
{
if (result.Button == MessageDialogButton.Yes)
{
//...
}
});
However, having a callback instead of a blocking method call like in MessageBox.Show yields absolutely no benefits for me. It makes things rather complicated. What I'm rather trying to achieve is something like...
if (MessageDialog.Confirmation(WindowMain.Singleton, true).Button == MessageDialogButton.Yes)
{
//...
}
... which is much cleaner in my opinion.
The current code behind is basically
Create instance of MessageDialog and populate content with text
Add it to the children of Window.Content.Children
On button click, call callback(result) and remove from Window.Content.Children
The question: What I would like to achieve is having a blocking method call instead of one that triggers a callback.
Even though the accepted answer seems to work, I propose a better solution using TaskCompletionSource. This is exactly what await was made for - it's still basically just a callback (won't block the thread), but your code looks a lot simpler when using it.
TaskCompletionSource<DialogResult> taskSource;
Task<DialogResult> ShowAsync()
{
return taskSource.Task;
}
public void OkButton_OnClick(EventArgs e, object sender)
{
taskSource.SetResult(DialogResult.OK);
}
public void CancelButton_OnClick(EventArgs e, object sender)
{
taskSource.SetResult(DialogResult.Cancel);
}
You then have to await the call: await Dialog.ShowAsync()
How about something like this:
//DialogControl.cs
bool _closed = false;
DialogResult _result;
DialogResult ShowModal()
{
this.Show();
while(!_closed) Application.DoEvents(); //Infinite loop
return _result;
}
public void OkButton_OnClick(EventArgs e, object sender)
{
_result = DialogResult.OK;
_closed = true;
}
public void CancelButton_OnClick(EventArgs e, object sender)
{
_result = DialogResult.Cancel;
_closed = true;
}
I have a class that talks to an external .exe. The class has a bunch of similar methods; they call a function of the .exe, wait for response, and then return true or false.
The response comes in the form of events that change the values of fields of this class.
Simplified code:
class Manager
{
private static bool connected = false;
public static bool Connect()
{
runtime.Connect();
int secondsWaited = 0;
while (!connected)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
}
The other methods use the same call-wait-loop-return structure.
My goal is to make a single method to do this waiting for me, like so:
private static bool WaitReferenceEqualsValue<T>(ref T reference, T value)
{
int secondsWaited = 0;
while (!reference.Equals(value))
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
Then each method would do:
runtime.DoSomething();
return WaitReferenceEqualsValue<someType>(ref someField, someSuccessfulValue);
However, when I replace the wait-loop with this method call, the field "connected", even though passed in as a reference, always stays the same.
Any idea what's going on here, and how to get the desired functionality?
Thanks in advance.
EDIT:
public static bool Connect()
{
...
runtime.Connect();
// this code works
/*int secondsWaited = 0;
while (connected != true)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}*/
// this somehow blocks OnConnect from firing, so connected never gets set to true
lock (typeof(SkypeKitManager))
{
WaitReferenceEqualsValue<bool>(ref connected, true);
}
...
}
OnConnect:
private static void OnConnect(object sender, Events.OnConnectArgs e)
{
if (e != null && e.success)
{
lock (typeof(Manager))
{
connected = true;
}
}
}
You're not doing any synchronization on that field although you access it from multiple threads and one of them is writing. This is a race (no exception! this is a race even if it looks safe. It isn't safe.).
Probably the JIT enregistered it which is a common optimization. It just never gets read from memory, always from a register. Add synchronization (for example a lock, or Interlocked or Volatile methods).
Your usage of ref is correct.
The problem with your code is essentially compiler optimization. Fo optimization purpose compilers (or jits) necessarily take a pretty much single threaded view. The compiler/jit will then notice that you don't touch reference in your code at all, therefore it can move the comparison outside the loop. It is free to do so, since you basically create a race condition (no synchronization/atomic accesses).
Fixing it could either involve using synchronization mechanisms or add the volatile specifier to reference, thus telling the compiler/jit, that the variable can be changed from outside the method.
My code doesn't terminate on a true condition if called from another method. For example,
void RunValidation()
{
if (NameEntered == string.Empty)
{
MessageBox.Show("No name has been entered");
return;
}
}
void CreateUser()
{
RunValidation();
//Run more code
}
If I call the validation method inside the create user method, the messagebox shows up but the rest of the code gets executed even though "return" was specified.
If the validation code is not inside a method and called directly in the CreateUser method, the rest of the code doesn't run (which is what I want). I want to be able to call a validation method inside many other methods and if the conditions are true, to stop executing other code in the methods.
What is the correct way of doing this? Do I have to use some sort of try and catch?
You are returning from the RunValidation method, not the CreateUser method. If you want to control the flow of the CreateUser method based on the results of RunValidation, do something like this:
bool Validate()
{
if (NameEntered.Equals(string.Empty))
{
MessageBox.Show("No name has been entered");
return false;
}
return true;
}
void CreateUser()
{
if (Validate())
{
// Run more code
}
}
The return statement only affects the current method. Read more about the return statement here.
return; exits the RunValidation() method.
It has no effect on the function that called it.
Instead, you should make RunValidation() return a boolean indicating whether the validation succeeded.
In the calling method, you can check if it returns false and return; from there too.
you can do something like:
bool RunValidation()
{
if (NameEntered == string.Empty)
{
MessageBox.Show("No name has been entered");
return false;
}
return true;
}
void CreateUser()
{
if(RunValidation())
{
//Run more code
}
}
U talking about this code block?
void RunValidation()
{
if (NameEntered == string.Empty)
{
MessageBox.Show("No name has been entered");
return;
}
}
because if you are, I don't know what "rest of code" it's executing, because there is no code after the return statement.
If you're talking about this
void CreateUser()
{
RunValidation();
//Run more code
}
then yes, just because RunValidation had a return statement doesn't mean that it's calling method will return. that kind of behavior would cause crazy bugs.
Now, in order to achieve yoru expected behavior, you can change runValidation to
bool RunValidation()
{
if (NameEntered == string.Empty)
{
MessageBox.Show("No name has been entered");
return false;
}
return true;
}
and then call it like
void CreateUser()
{
if(RunValidation())
{
//Run more code
}
}
depending on the do work method my result could either be a List of Strings or a list of byte[]
How can we check the RunWorkerCompletedEventArgs e -
if (e is List<String>)
is this the correct way to check?
No, this is not the right way.
The correct way is to use this:
if(e.Result is List<string>)
{
//...
}
else if(e.Result is List<byte[]>)
{
//...
}
else
{
//...
}
e will always be of type RunWorkerCompletedEventArgs. But this class contains a property Result that contains the result of your DoWork event handler. That's the one, you need to check.
Yes, that's one possible way to do it.
If you only have two types it would be quite easy:
if(e.Result is List<string>)
{
}
else if(e.Result is List<byte[]>)
{
}
else
{
}
But the problem comes in to play if you have to support more than just two or three. In that case i'm going to create a Dictionary<Type, Action<object>> and write individual functions for each type. Something like this:
var supportedTypes = new Dictionary<Type, Action<object>>();
supportedTypes.Add(typeof(List<string>), ComputeListOfStrings);
supportedTypes.Add(typeof(List<byte[]>), ComputeListOfByteArrays);
private void ComputeListOfString(object listOfStrings)
{
var list = (List<string>)listOfStrings;
}
private void ComputeListOfByteArrays(object listOfByteArrays)
{
var list = (List<byte[]>)listOfByteArrays;
}
This makes it more simple to support new types and also stays to be O(1) while the if-else-if runs into the order-matters problem.
Used will this in your background worker as followed:
worker.OnRunWorkerCompleted += (sender, e) =>
{
Action<object> supportedAction;
supportedTypes.TryGetValue(e.Result.GetType(), out supportedAction);
if(supportedAction != null)
{
supportedAction();
}
};
the e.Result is the property with your results, so to get the type you can do:
if(e.Result.GetType().Equals(typeof(List<String>)))