Binding behaviour regarding exceptions

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mikus Sleiners

    Binding behaviour regarding exceptions

    Is there any way to enable exception throws in VS 2005, that occur during
    binding operations?

    I am upset that i can't see exceptions that are thrown during binding
    operations. It's very hard to track down erroneous behaviour of your app if
    you can't see where the problem is... i mean it's realy hard to debug
    binding issues and it would be realy of help if i could somehow enable this
    during debug session.



  • Marc Gravell

    #2
    Re: Binding behaviour regarding exceptions

    Try catching the BindingComplete event for a Binding, where
    e.BindingComple teState== BindingComplete State.Exception and look at
    e.Exception.

    You should be able to walk the Controls and their Bindings to attach the
    handler globally; you can also subclass Binding and do it that way (I think
    there is a virtual OnBindingComple te method) - but this won't catch those
    added with DataBindings.Ad d("Text",obj,"P roperty"), since it will create a
    vanilla Binding instance.

    Any use?

    Marc


    Comment

    • Walter Wang [MSFT]

      #3
      RE: Binding behaviour regarding exceptions

      Hi Mikus,

      Internally, the Binding class will handle the bound control's Validate
      event:

      private void Target_Validate (object sender, CancelEventArgs e)
      {
      try
      {
      if (this.PullData( true))
      {
      e.Cancel = true;
      }
      }
      catch
      {
      e.Cancel = true;
      }
      }

      That's why the exception is eaten silently.

      To catch the exception during debugging, I recommend first use your custom
      exception class to throw:

      public class MyValidateExcep tion : Exception
      { }

      public int Currency
      {
      get { return _currency; }
      set
      {
      if (value == 2)
      {
      throw new MyValidateExcep tion();
      }
      ...

      Then in Visual Studio IDE, open menu "Debug/Exception...", click button
      "Add...", select type "Common Language Runtime Exceptions", input your
      exception class's full name (including namespace) in the field "Name". When
      added, make sure it's checked in the "Thrown" column.

      This way, the exception will be caught everytime it's thrown regardless
      there're try/catch handler or not.

      By the way, although the exception is not displayed during debugging, the
      output window of IDE should log the exception such as:

      A first chance exception of type
      'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
      control_bind_no t_refresh_displ ay.exe
      A first chance exception of type
      'System.Reflect ion.TargetInvoc ationException' occurred in mscorlib.dll
      A first chance exception of type
      'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
      System.dll
      A first chance exception of type
      'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
      System.Windows. Forms.dll

      Though it lacks of information such as exception location.

      Sincerely,
      Walter Wang (wawang@online. microsoft.com, remove 'online.')
      Microsoft Online Community Support

      =============== =============== =============== =====
      Get notification to my posts through email? Please refer to
      Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

      ications. If you are using Outlook Express, please make sure you clear the
      check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
      promptly.

      Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
      where an initial response from the community or a Microsoft Support
      Engineer within 1 business day is acceptable. Please note that each follow
      up response may take approximately 2 business days as the support
      professional working with you may need further investigation to reach the
      most efficient resolution. The offering is not appropriate for situations
      that require urgent, real-time or phone-based interactions or complex
      project analysis and dump analysis issues. Issues of this nature are best
      handled working with a dedicated Microsoft Support Engineer by contacting
      Microsoft Customer Support Services (CSS) at
      http://msdn.microsoft.com/subscripti...t/default.aspx.
      =============== =============== =============== =====

      This posting is provided "AS IS" with no warranties, and confers no rights.


      Comment

      • Mikus Sleiners

        #4
        Re: Binding behaviour regarding exceptions

        Hi!
        Thanks for information. This is new for me, but it does not help because I
        would like to see all exceptions like NoReferenceFoun dException,
        DivideByZeroExc eption and so on!

        We have a bunch of properties and it would be insane to write try catch
        blocks for all of them.


        "Walter Wang [MSFT]" <wawang@online. microsoft.comwr ote in message
        news:deCi4%23I3 GHA.4280@TK2MSF TNGXA01.phx.gbl ...
        Hi Mikus,
        >
        Internally, the Binding class will handle the bound control's Validate
        event:
        >
        private void Target_Validate (object sender, CancelEventArgs e)
        {
        try
        {
        if (this.PullData( true))
        {
        e.Cancel = true;
        }
        }
        catch
        {
        e.Cancel = true;
        }
        }
        >
        That's why the exception is eaten silently.
        >
        To catch the exception during debugging, I recommend first use your custom
        exception class to throw:
        >
        public class MyValidateExcep tion : Exception
        { }
        >
        public int Currency
        {
        get { return _currency; }
        set
        {
        if (value == 2)
        {
        throw new MyValidateExcep tion();
        }
        ...
        >
        Then in Visual Studio IDE, open menu "Debug/Exception...", click button
        "Add...", select type "Common Language Runtime Exceptions", input your
        exception class's full name (including namespace) in the field "Name".
        When
        added, make sure it's checked in the "Thrown" column.
        >
        This way, the exception will be caught everytime it's thrown regardless
        there're try/catch handler or not.
        >
        By the way, although the exception is not displayed during debugging, the
        output window of IDE should log the exception such as:
        >
        A first chance exception of type
        'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
        control_bind_no t_refresh_displ ay.exe
        A first chance exception of type
        'System.Reflect ion.TargetInvoc ationException' occurred in mscorlib.dll
        A first chance exception of type
        'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
        System.dll
        A first chance exception of type
        'control_bind_n ot_refresh_disp lay.MyValidateE xception' occurred in
        System.Windows. Forms.dll
        >
        Though it lacks of information such as exception location.
        >
        Sincerely,
        Walter Wang (wawang@online. microsoft.com, remove 'online.')
        Microsoft Online Community Support
        >
        =============== =============== =============== =====
        Get notification to my posts through email? Please refer to
        Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

        ications. If you are using Outlook Express, please make sure you clear the
        check box "Tools/Options/Read: Get 300 headers at a time" to see your
        reply
        promptly.
        >
        Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
        where an initial response from the community or a Microsoft Support
        Engineer within 1 business day is acceptable. Please note that each follow
        up response may take approximately 2 business days as the support
        professional working with you may need further investigation to reach the
        most efficient resolution. The offering is not appropriate for situations
        that require urgent, real-time or phone-based interactions or complex
        project analysis and dump analysis issues. Issues of this nature are best
        handled working with a dedicated Microsoft Support Engineer by contacting
        Microsoft Customer Support Services (CSS) at
        http://msdn.microsoft.com/subscripti...t/default.aspx.
        =============== =============== =============== =====
        >
        This posting is provided "AS IS" with no warranties, and confers no
        rights.
        >
        >

        Comment

        • Marc Gravell

          #5
          Re: Binding behaviour regarding exceptions

          Then perhaps the following?

          Most binding operations will consider ICustomTypeDesc riptor; if you
          implement this interface on your object (or better, a base object), and
          forward most of the calls to TypeDescriptor, except for GetProperties; in
          this one you could call TypeDescriptor. GetProperties using "this" as the
          component, but wrap each returned property in a bespoke PropertyDescrip tor
          that forwards all calls to the existing (reflective) descriptor, but adds
          exception handling to the GetValue and SetValue members.

          It sounds complex, but I have code that will do most of this if you want;
          I'm not going to put forward an example unless you are interested, though.

          Let me know,

          Marc


          Comment

          • Marc Gravell

            #6
            Re: Binding behaviour regarding exceptions

            I got bored... here you go... add code to "TODO":

            using System;
            using System.Collecti ons.Generic;
            using System.Windows. Forms;
            using System.Componen tModel;

            namespace WindowsApplicat ion2 {
            static class Program {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main() {
            Application.Ena bleVisualStyles ();
            Application.Set CompatibleTextR enderingDefault (false);
            List<SomeClassl ist = new List<SomeClass> ();
            list.Add(new SomeClass());
            list.Add(new SomeClass());
            list.Add(new SomeClass());
            using (Form f = new Form())
            using (DataGridView dgv = new DataGridView()) {
            dgv.Dock = DockStyle.Fill;
            f.Controls.Add( dgv);
            dgv.DataSource = list;
            Application.Run (f);
            }
            }
            }
            public class SomeClass : ICustomTypeDesc riptor {
            private string name = "";
            public string Name {
            get { return name; }
            set {
            if (value == "Fred") throw new InvalidOperatio nException();
            name = value; }
            }
            private int number;
            public int Number {
            get { return number; }
            set { number = value; }
            }

            AttributeCollec tion ICustomTypeDesc riptor.GetAttri butes() {
            return TypeDescriptor. GetAttributes(G etType());
            }
            string ICustomTypeDesc riptor.GetClass Name() {
            return TypeDescriptor. GetClassName(Ge tType());
            }
            string ICustomTypeDesc riptor.GetCompo nentName() {
            return TypeDescriptor. GetComponentNam e(GetType());
            }
            TypeConverter ICustomTypeDesc riptor.GetConve rter() {
            return TypeDescriptor. GetConverter(Ge tType());
            }
            EventDescriptor ICustomTypeDesc riptor.GetDefau ltEvent() {
            return TypeDescriptor. GetDefaultEvent (GetType());
            }
            PropertyDescrip tor ICustomTypeDesc riptor.GetDefau ltProperty() {
            return TypeDescriptor. GetDefaultPrope rty(GetType());
            }
            object ICustomTypeDesc riptor.GetEdito r(Type editorBaseType) {
            return TypeDescriptor. GetEditor(GetTy pe(), editorBaseType) ;
            }
            EventDescriptor Collection
            ICustomTypeDesc riptor.GetEvent s(Attribute[] attributes) {
            return TypeDescriptor. GetEvents(GetTy pe(), attributes);
            }
            EventDescriptor Collection ICustomTypeDesc riptor.GetEvent s() {
            return TypeDescriptor. GetEvents(GetTy pe());
            }
            PropertyDescrip torCollection
            ICustomTypeDesc riptor.GetPrope rties(Attribute[] attributes) {
            return WrapProps(TypeD escriptor.GetPr operties(GetTyp e(),
            attributes));
            }
            PropertyDescrip torCollection ICustomTypeDesc riptor.GetPrope rties() {
            return WrapProps(TypeD escriptor.GetPr operties(GetTyp e()));
            }
            private PropertyDescrip torCollection
            WrapProps(Prope rtyDescriptorCo llection props) {
            PropertyDescrip tor[] newProps = new
            PropertyDescrip tor[props.Count];
            int i = 0;
            foreach(Propert yDescriptor prop in props) {
            newProps[i++] = new ErrorLoggingPro pertyDescriptor (prop);
            }
            return new PropertyDescrip torCollection(n ewProps, true);
            }
            object ICustomTypeDesc riptor.GetPrope rtyOwner(Proper tyDescriptor pd)
            {
            return this;
            }
            }
            public class ErrorLoggingPro pertyDescriptor :
            ForwardingPrope rtyDescriptor {
            public ErrorLoggingPro pertyDescriptor (PropertyDescri ptor root) :
            base(root){}
            public override object GetValue(object component) {
            try {
            return base.GetValue(c omponent);
            } catch (Exception ex) {
            // TODO: do something with ex
            throw;
            }
            }
            public override void SetValue(object component, object value) {
            try {
            base.SetValue(c omponent, value);
            } catch (Exception ex) {
            // TODO: do something with ex
            throw;
            }
            }

            }
            public abstract class ForwardingPrope rtyDescriptor : PropertyDescrip tor
            {
            private readonly PropertyDescrip tor _root;
            protected PropertyDescrip tor Root { get { return _root; } }
            protected ForwardingPrope rtyDescriptor(P ropertyDescript or root)
            : base(root) {
            _root = root;
            }
            public override void AddValueChanged (object component, EventHandler
            handler) {
            Root.AddValueCh anged(component , handler);
            }
            public override AttributeCollec tion Attributes {
            get {
            return Root.Attributes ;
            }
            }
            public override bool CanResetValue(o bject component) {
            return Root.CanResetVa lue(component);
            }
            public override string Category {
            get {
            return Root.Category;
            }
            }
            public override Type ComponentType {
            get { return Root.ComponentT ype; }
            }
            public override TypeConverter Converter {
            get {
            return Root.Converter;
            }
            }
            public override string Description {
            get {
            return Root.Descriptio n;
            }
            }
            public override bool DesignTimeOnly {
            get {
            return Root.DesignTime Only;
            }
            }
            public override string DisplayName {
            get {
            return Root.DisplayNam e;
            }
            }
            public override bool Equals(object obj) {
            return Root.Equals(obj );
            }
            public override PropertyDescrip torCollection
            GetChildPropert ies(object instance, Attribute[] filter) {
            return Root.GetChildPr operties(instan ce, filter);
            }
            public override object GetEditor(Type editorBaseType) {
            return Root.GetEditor( editorBaseType) ;
            }
            public override int GetHashCode() {
            return Root.GetHashCod e();
            }
            public override object GetValue(object component) {
            return Root.GetValue(c omponent);
            }
            public override bool IsBrowsable {
            get {
            return Root.IsBrowsabl e;
            }
            }
            public override bool IsLocalizable {
            get {
            return Root.IsLocaliza ble;
            }
            }
            public override bool IsReadOnly {
            get { return Root.IsReadOnly ; }
            }
            public override string Name {
            get {
            return Root.Name;
            }
            }
            public override Type PropertyType {
            get { return Root.PropertyTy pe; }
            }
            public override void RemoveValueChan ged(object component,
            EventHandler handler) {
            Root.RemoveValu eChanged(compon ent, handler);
            }
            public override void ResetValue(obje ct component) {
            Root.ResetValue (component);
            }
            public override void SetValue(object component, object value) {
            Root.SetValue(c omponent, value);
            }
            public override bool ShouldSerialize Value(object component) {
            return Root.ShouldSeri alizeValue(comp onent);
            }
            public override bool SupportsChangeE vents {
            get {
            return Root.SupportsCh angeEvents;
            }
            }
            public override string ToString() {
            return Root.ToString() ;
            }
            }
            }


            Comment

            • Walter Wang [MSFT]

              #7
              Re: Binding behaviour regarding exceptions

              Hi Mikus,

              I've done more research on this issue and found more information to share
              with you.

              From document of Binding.Formatt ingEnabled [4]:

              Setting this property to true also enables error-handling behavior and
              causes the BindingComplete event to be raised. The handler of this event
              can take the appropriate action, based on the success, error, or exceptions
              in the binding process, by examining the BindingComplete State property of
              the BindingComplete EventArgs parameter.

              So we need to follow Marc's suggestion in his first reply:

              private void class1BindingSo urce_BindingCom plete(object sender,
              BindingComplete EventArgs e)
              {
              if (e.BindingCompl eteState == BindingComplete State.Exception )
              {
              MessageBox.Show (e.Exception.Me ssage );
              }
              }

              But this need the FormattingEnabl ed property of the Binding class set to
              true. If it's false, the exception will just get consumed by the Binding
              class and never has a chance to report back.

              However, this requirement conflicts with the other issue you've mentioned
              in [1]; which is also reported as a known bug [2]. So my workaround in that
              post is not completely working: it will cause this issue you're
              experiencing. I must apologize for the confusion I've caused.

              So, I think we will just make sure the FormattingEnabl ed property set to
              true as the designer generated code did that for us. We will need find
              another workaround to deal with the bug mentioned in [1] and [2].

              We can use following workaround instead:

              In the business object's PropertyChanged event, we can flip the
              FormattingEnabl ed property of the Binding to make it reflect the changed
              property value back to the source:

              Class c1 = new Class1();
              c1.PropertyChan ged += new
              PropertyChanged EventHandler(c1 _PropertyChange d);

              ...

              void c1_PropertyChan ged(object sender, PropertyChanged EventArgs e)
              {
              foreach (Binding b in textBox1.DataBi ndings)
              {
              if (b.IsBinding && b.BindingMember Info.BindingMem ber ==
              e.PropertyName)
              {
              b.FormattingEna bled = !b.FormattingEn abled;
              b.FormattingEna bled = !b.FormattingEn abled;
              }
              }

              // you may need to handle other controls' DataBindings too
              }

              Please let me know what do you think of above workaround. Thanks.

              References:

              [1] #Control bind to object does not refresh it's display in
              dotnet.language s.csharp
              Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

              c.dotnet.langua ges.csharp&tid= 31384fbc-a888-4286-b6c9-c3be53e77e5e&m= 1&p=1

              [2] #Feedback: Current control doesn't refresh values due to
              PropertyChanged event

              kID=115342

              [3] #Binding behaviour regarding exceptions in dotnet.language s.csharp
              Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

              c.dotnet.langua ges.csharp&mid= 72e21545-078c-4676-96aa-46c481827590&sl oc=en-u
              s&m=1

              [4] #Binding.Format tingEnabled Property (System.Windows .Forms)

              tingenabled.asp x

              Regards,
              Walter Wang (wawang@online. microsoft.com, remove 'online.')
              Microsoft Online Community Support

              =============== =============== =============== =====
              When responding to posts, please "Reply to Group" via your newsreader so
              that others may learn and benefit from your issue.
              =============== =============== =============== =====

              This posting is provided "AS IS" with no warranties, and confers no rights.

              Comment

              Working...