|
That's nasty!
Damn good idea, but nasty all the same...don't think there is a tidy solution for this, so it gets my vote.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952)
Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
|
|
|
|
|
OriginalGriff wrote: That's nasty! Agreed.
OK then, I suggest not throwing an exception and instead simply having the consumer of the wrapper subscribe to the wrapper's OnError() handler.
/ravi
|
|
|
|
|
Trouble is...I'm not sure that even with an event the return will be executed at all times...if the exception isn't caught by anything, I think the app will crash. And I'm pretty sure that the exception will be immediately executed on the same thread and will pop the stack all the way back to the exception handler without ever hitting the instruction after the one raising the event...
This is nastier than I thought...I'm not sure there is any way to do this, short of a timer which is truly horrible!
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952)
Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
|
|
|
|
|
Griff is correct, this won't work – event handlers are called in the same thread, so if you re-fire an event and a delegate down the line throws an exception, your own handler code won't complete and you'll never return true to the library code.
This kind of thing is why it's usually considered a Bad Idea (TM) to throw exceptions in event handlers.
|
|
|
|
|
I agree with Ravi's solution, it's not perfect but I can't think of a better solution.
If you have the source code of the Third Party component or if there is a way to get them to change the component for you, you can ask them to include a parameter to indicate if the error was handled rather than returning true/false. Something like this:
protected void Session_ErrorOccurred(string id, string message, bool handled)
{
handled = true;
throw new SASException(id, message);
}
This signature still violates the Framework Design Guidelines for Events. It should ideally be like this:
protected void Session_ErrorOccurred(object sender, ErrorEventArgs args)
{
args.handled = true;
throw new SASException(args.id, args.message);
}
modified 5-Mar-14 11:14am.
|
|
|
|
|
This could get really ugly. You must allow the method to complete, so the library gets its result back, but you'd like the managed code to die with an exception as soon as an error occurs.
What is the exact conditions under which this delegate can get called? Is it that any call to third party library code could case OnError to be called, and then your code will continue afterwards?
I don't really see an alternative to
Library.CallToSomething();
if(ErrorWasRaised) throw new MyException("...");
Library.CallToSomethingElse();
if(ErrorWasRaised) throw new MyException("...");
... where ErrorWasRaised is instance state that's assigned from your OnError handler.
The only thing I can think of is to hide the ugliness in a utility method with a lambda:
void CallErrorHandlingLibraryCode(Action code) {
string errorId = null, errorMessage = null;
OnErrorHandler errorLogger = (id, message) => {
errorId = id; errorMessage = message;
return true;
};
Library.OnError += errorLogger;
try {
code();
if(null != errorId)
throw new SASException(errorId, errorMessage);
} finally {
Library.OnError -= errorLogger;
}
}
Then your calling code looks like
CallErrorHandlingLibraryCode(() => Library.CallToSomething());
CallErrorHandlingLibraryCode(() => Library.CallToSomethingElse());
... which is arguably better looking depending on your taste in lambdas.
|
|
|
|
|
If you are able to catch the exception and understand when it could occur then you shouldn't throw it. What you are trying to do is notify on the event. If you were throwing an exception then it would be fine to now return true. I know, seems counter-intuitive since all of the MS sample code is littered with throw exceptions every where but if you design with that in mind, your world can be a much better place. I have a lot of third-party libraries were I would kill for the ability to not have an exception.
|
|
|
|
|
The concept is wrong.
An exception must propagate the call stack of a thread.
Presumably what you want is the following
public void Call3rdparty()
{
try
{
Component.ErrorOccurred = MyErrorMethod;
Component.CallMethod()
}
catch(SASException e)
{
}
}
The problem with the above is that there is no assurance that MyErrorMethod will be called in the same thread as Call3rdparty
This means that the call semantics are implicitly asynchronous and it must be handled that way.
I believe there are some handy classes in C#/Net that allows one to create a async call but it isn't that hard to write one yourself using a monitor (or whatever it is called), timeout and appropriate attributes. If creating it yourself
- Create a thread to call the method -
- Set a monitor, with timeout
- If thread returns then set a flag, and set monitor
- If error method is called set attribute that indicates error
- Once monitor clears (excluding timeout) then check attribute for error, if there is error then throw exception
|
|
|
|
|
You are right. Thinking of the problem after my post, I came to a similar reasoning.
The error occurs somewhere in ThirdParty - though that process was somehow started through our code, it is quite un-coupled from it: we instantiate a class of their .Net SDK, call a Start method, which then communicates with ThirdParty server (that is on a different computer, could also be hosted in ThirdParty's cloud). On the server, the processing is started in a new thread, and the call to Start returns. When an error occurs in that new processing thread on the server, where could it be thrown to - it always travels the CallStack "upwards"? The Start method has long returned! Consequently, ThirdParty must use an event to communicate "downwards" to an "Observer". Hence I'll create a .Net event and raise that - then it is wrapped properly.
|
|
|
|
|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
SqlConnection sc=new SqlConnection (@"Data Source=.\SQLEXPRESS; AttachDbFilename=phonebook.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
SqlCommand cmd;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
sc.Open();
cmd = new SqlCommand("Insert into emails(id, emails, pbid) values('" + txtId.Text + "','" + txtEm.Text + "','" + txtPbid.Text + "')",sc);
cmd.ExecuteNonQuery();
MessageBox.Show("Update Successfull to the database");
sc.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
|
|
|
|
|
Start by fixing the SQL Injection vulnerability[^] in your code:
private void btnSave_Click(object sender, EventArgs e)
{
try
{
sc.Open();
using (SqlCommand cmd = new SqlCommand("INSERT INTO emails (id, emails, pbid) VALUES (@id, @emails, @pbid)"))
{
cmd.Parameters.AddWithValue("@id", txtId.Text);
cmd.Parameters.AddWithValue("@emails", txtEm.Text);
cmd.Parameters.AddWithValue("@pbid", txtPbid.Text);
cmd.ExecuteNonQuery();
MessageBox.Show("Update Successfull to the database");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
System.Diagnostics.Debug.WriteLine(ex);
}
finally
{
sc.Close();
}
}
If it still doesn't work, you'll need to post the error message. Look in the debug output in Visual Studio to get the full details.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
You do know that you need to reply to the original poster don't you? Richard doesn't need your help and the OP won't be informed that you have posted a reply because it's not against them.
|
|
|
|
|
He's a spammer. The link from his signature & profile page
thatrajaCode converters | Education Needed
No thanks, I am all stocked up. - Luc Pattyn
When you're wrestling a gorilla, you don't stop when you're tired, you stop when the gorilla is - Henry Minute
|
|
|
|
|
My debug output information is:
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\bayaraa\Documents\Visual Studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.vshost.exe', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Deployment\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Deployment.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 'vshost.NotifyLoad' (0xc44) has exited with code 0 (0x0).
The thread '<No Name>' (0x44c) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x63c) has exited with code 0 (0x0).
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\bayaraa\Documents\Visual Studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe', Symbols loaded.
'WindowsFormsApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread '<No Name>' (0x1494) has exited with code 0 (0x0).
The thread 'vshost.RunParkingWindow' (0xc8c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1644) has exited with code 0 (0x0).
The program '[4284] WindowsFormsApplication1.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
|
|
|
|
|
|
Hi,
What error message are you getting?
More information would help...
Tempo Allegro
Neva Bull
|
|
|
|
|
don't error. but don't saving to sql server. i don't understand
|
|
|
|
|
I'm mongolia. I'm a beginner of C#, so my English level is really poor.
|
|
|
|
|
Could someone help me with a video or picture description please?
|
|
|
|
|
Hello everyone,
I found that i can use bindinglist as datasource, now when i implement in a griedview datasource i came up with a problem that i cant track which item has been modified. so i make a little research and found about the INotifyPropertyChanged and will trigger if there is data that has been modified.
but what i need is a list of item that has been modified. not triggering an event for every property of the object that has been modified, and also found out that implementing INotifyPropertyChanged can cause some drawback in performance as i read in some blog.
so i came up inheriting bindinglist and add some features, without implementing NotifyPropertyChanged in the item class.
so this is my solution.
First the IEditableObject
namespace gcsc.Interface
{
public interface IEditableObject
{
bool IsNew();
void IsNew(bool status);
bool IsDirty();
void IsDirty(bool status);
}
}
then the class that should be inherited by the item
namespace gcsc.UI
{
public abstract class EditableObject : Interface.IEditableObject
{
private bool _isNew;
private bool _isDirty;
public bool IsNew()
{
return _isNew;
}
public void IsNew(bool status)
{
_isNew = status;
}
public bool IsDirty()
{
return _isDirty;
}
public void IsDirty(bool status)
{
_isDirty = status;
}
}
}
then that last is the GCSCBindingList<t> that will inherit the binding list
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using GI = gcsc.Interface;
namespace gcsc.Util
{
public sealed class GCSCBindingList<T> : BindingList<T>
{
private readonly List<T> _removeItems;
private readonly bool _initValues;
public IEnumerable<T> GetRemovedItems()
{
return _removeItems.AsEnumerable();
}
public IEnumerable<T> GetUpdatedItems()
{
foreach (GI.IEditableObject item in this)
{
if (item.IsDirty())
yield return (T)item;
}
}
public IEnumerable<T> GetNewItems()
{
foreach (GI.IEditableObject item in this)
{
if (item.IsNew())
yield return (T)item;
}
}
public GCSCBindingList()
{
if (!typeof(T).ImplementsInterface<GI.IEditableObject>())
throw new ArrayTypeMismatchException("T must implement gcsc.Interface.IEditableObject");
_removeItems = new List<T>();
AllowEdit = true;
AllowNew = true;
AllowRemove = true;
}
public GCSCBindingList(IList<T> list)
{
if (!typeof(T).ImplementsInterface<GI.IEditableObject>())
throw new ArrayTypeMismatchException("T must implement gcsc.Interface.IEditableObject");
_removeItems = new List<T>();
AllowEdit = true;
AllowNew = true;
AllowRemove = true;
_initValues = true;
foreach (var v in list)
base.Add(v);
_initValues = false;
}
protected override void InsertItem(int index, T item)
{
if (!_initValues)
((GI.IEditableObject)item).IsNew(true);
base.InsertItem(index, item);
}
public new void Insert(int index, T item)
{
((GI.IEditableObject)item).IsNew(true);
base.Insert(index, item);
}
protected override void RemoveItem(int index)
{
if (index >= 0 && index < base.Count)
{
var item = base[index];
_removeItems.Add(item);
base.RemoveItem(index);
}
}
}
}
Now with the GCSCBindingList<T>
i can retrieve all deleted items and all the new items, but still i cant find a way to collect all edited items.
the IsDirty(bool status) method should set to true if the item has been modified, but i cant find the way to implement this.
Could you help me do this?
this is my sample usage, first the class
public class person : gcsc.UI.EditableObject
{
public person()
{
}
public person(string lastname, string firstname)
{
LastName = lastname;
FirstName = firstname;
}
public override string ToString()
{
return string.Format("{0}, {1} status new:{2}, dirty:{3}", LastName, FirstName, IsNew(), IsDirty());
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
then can be used like this
List<person> p = new List<person>();
p.Add(new person("John", "smith"));
p.Add(new person("pual", "carl"));
GB = new gcsc.Util.GCSCBindingList<person>(p);
private void simpleButton1_Click(object sender, EventArgs e)
{
GB.RemoveAt(0);
foreach (person p in GB.GetNewItems())
{
XtraMessageBox.Show(p.ToString());
}
foreach (person p in GB.GetRemovedItems())
{
XtraMessageBox.Show(p.ToString());
}
foreach (person p in GB.GetUpdatedItems())
{
MessageBox.Show(p.ToString());
}
}
now the GB.GetUpdatedItems() is empty because the IsDirty() is still return false even there is item edited.
Is there way enumerating all edited items?
Please help me solving this problem.
I Will appreciate for any help will come.
Thank you,
PS. sorry for my bad english
|
|
|
|
|
Implementing INotifyPropertyChanged on your item class (e.g. Person) will cause a BindingList to fire ListChanged (subtype ItemChanged) events whenever your object fires a property notification event (usually in property setters). You can then hook up to that to store a list of what's been touched. It will also ensure that whatever you bind the list to in your UI will get updated when the items actually change.
Putting INotifyPropertyChanged on your domain objects is a bit ugly but I think it's the right way to go here.
|
|
|
|
|
Thank you for the reply
BobJanova wrote: Putting INotifyPropertyChanged on your domain objects is a bit ugly but I think it's the right way to go here.
yes your right.
That is the main purpose of GCSCBindingList<t>, creating object without implementing INotifyPropertyChanged.
I am still digging on the internet for solution.
Trying to figure out how to implement IBindingList instead of BindingList<t> as my last resort.
But if i cant figure it, there is nothing i can do but to implement INotifyPropertyChanged.
|
|
|
|
|
I think INotifyPropertyChanged is not good to implement, there is some articles saying that, implementing INotifyPropertyChanged will cause performance issue.
modified 7-Mar-14 3:57am.
|
|
|
|
|
Implementing INPC will cause your property getters to be called every time you notify the binding list that a property is changed. If you have expensive property getters (e.g. talking to an external data source), that could cause a problem – best practice is not to do that. If you're updating a lot of properties on the same item repeatedly, you'll want some kind of BeginUpdate/EndUpdate mechanism whereby you can turn off notifications while you make a lot of changes.
|
|
|
|
|