Re: Linq-SQL canonical editable datagridview sample code

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

    Re: Linq-SQL canonical editable datagridview sample code

    Marc,
    >I don't know if there is an easier way, but how about:
    Thank you very much. I have issue on implementing add row properly using
    this.

    User presses down arrow in last row in grid starting adding new row.
    Then user changes its mind desiding that new row should not added and
    presses up arrow.
    DataGridView does not show this unfinished row anymore.

    However entity remains in DataContext and is added to database on
    SubmitChanges.
    How to prevent this ghost entity addition ?

    Andrus.


  • Marc Gravell

    #2
    Re: Linq-SQL canonical editable datagridview sample code

    Probably you'd need to implement ICancelAddNew, but taking a peek,
    BindingList<Tal ready does this, calling RemoveItem correctly...
    hmmm... I'll investigate...

    Comment

    • Marc Gravell

      #3
      Re: Linq-SQL canonical editable datagridview sample code

      I've looked at this with LINQ-to-SQL, and I cannot reproduce the
      issue; if I add and remove a row (in any combination of immediate and
      delayed cancel), then no change is applied to the database.

      So: are you using LINQ-to-SQL, or are you using DbLinq? If the latter,
      then I suspect it has "issues" noticing this trivial change (trivial
      meant in the literal sense - not intended to be patronising).

      You might be able to write the list to track insertions itself, but
      this should be the job of the data-context. Of course, if this
      actually is LINQ-to-SQL, please let me know and I'll retry...

      Marc

      Comment

      • Andrus

        #4
        Re: Linq-SQL canonical editable datagridview sample code

        Marc,
        >Probably you'd need to implement ICancelAddNew, but taking a peek,
        >BindingList<Ta lready does this, calling RemoveItem correctly...
        I observed the following:

        1. Pressing down arrow in last line of DataGridView calls AddNewCore() which
        adds new entity to
        DataContext.

        2. Pressing Up Arrow doest *not* call RemoveItem. So added fake entity will
        me saved on SubmitChanges() .

        I'm wondering how Linq-SQL performs this correctly since RemoveItem() is not
        called.

        I'm using DbLinq but this should not depend on Linq provider.

        Andrus.


        Comment

        • Andrus

          #5
          Re: Linq-SQL canonical editable datagridview sample code

          Marc,
          I've looked at this with LINQ-to-SQL, and I cannot reproduce the
          issue; if I add and remove a row (in any combination of immediate and
          delayed cancel), then no change is applied to the database.
          I'm planning to fix this in the following way:

          1. AddNewCode() assigns new entity to property only, will not add to
          DataContext
          2. Override ICancelAddNew EndNew() method and add new entity to DataContext
          in this method.

          Will this work OK ?

          Andrus.


          Comment

          • Marc Gravell

            #6
            Re: Linq-SQL canonical editable datagridview sample code

            Probably - but you can't *fully* verify the cancel conditions (the
            index etc) since they aren't available as protected... I added
            Console.WriteLi ne to RemoveItem, and it seemed to be working fine...

            Marc

            Comment

            • Andrus

              #7
              Re: Linq-SQL canonical editable datagridview sample code

              Marc,
              Probably - but you can't *fully* verify the cancel conditions (the
              index etc) since they aren't available as protected... I added
              Console.WriteLi ne to RemoveItem, and it seemed to be working fine...
              I found that this occurs only when I move up-down in my
              CustomDataGridV iewComBobox column.

              Down arrow in this column invokes AddNewCore().
              Up arrow does *not* invoke RemoveItem.
              Pressing down arrow again causes InvalidOperatio nException in
              base.AddNewCore ()

              It seems that my combobox column class blocks bindinglist RemoveItem call.
              I checked my class overridden methods and it seems that I'm calling base
              methods in most cases.
              Which combobox columns method calls bindinglist RemoveItem() ?
              I implemented combobox column using MSDN sample code.

              Any idea how to debug / resolve this issue? Exception which I got is below.

              Andrus.

              System.InvalidO perationExcepti on was unhandled
              Message="Operat ion is not valid due to the current state of the object."
              Source="System. Windows.Forms"
              StackTrace:
              at
              System.Windows. Forms.DataGridV iew.DataGridVie wDataConnection .ProcessListCha nged(ListChange dEventArgs
              e)
              at
              System.Windows. Forms.DataGridV iew.DataGridVie wDataConnection .currencyManage r_ListChanged(O bject
              sender, ListChangedEven tArgs e)
              at
              System.Windows. Forms.CurrencyM anager.OnListCh anged(ListChang edEventArgs e)
              at System.Windows. Forms.CurrencyM anager.List_Lis tChanged(Object
              sender, ListChangedEven tArgs e)
              at
              System.Componen tModel.BindingL ist`1.OnListCha nged(ListChange dEventArgs e)
              at System.Componen tModel.BindingL ist`1.InsertIte m(Int32 index, T
              item)
              at System.Collecti ons.ObjectModel .Collection`1.A dd(T item)
              at System.Componen tModel.BindingL ist`1.AddNewCor e()
              at MyAppl.TableLis t`1.AddNewCore( ) in I:\MyAppl\Table List.cs:line 92
              at
              System.Componen tModel.BindingL ist`1.System.Co mponentModel.IB indingList.AddN ew()
              at System.Windows. Forms.CurrencyM anager.AddNew()
              at
              System.Windows. Forms.DataGridV iew.DataGridVie wDataConnection .AddNew()
              at
              System.Windows. Forms.DataGridV iew.DataGridVie wDataConnection .OnNewRowNeeded ()
              at System.Windows. Forms.DataGridV iew.OnRowEnter( DataGridViewCel l&
              dataGridViewCel l, Int32 columnIndex, Int32 rowIndex, Boolean
              canCreateNewRow , Boolean validationFailu reOccurred)
              at System.Windows. Forms.DataGridV iew.SetCurrentC ellAddressCore( Int32
              columnIndex, Int32 rowIndex, Boolean setAnchorCellAd dress, Boolean
              validateCurrent Cell, Boolean throughMouseCli ck)
              at System.Windows. Forms.DataGridV iew.ProcessDown KeyInternal(Key s
              keyData, Boolean& moved)
              at System.Windows. Forms.DataGridV iew.ProcessDown Key(Keys keyData)
              at
              System.Windows. Forms.DataGridV iew.ProcessData GridViewKey(Key EventArgs e)
              at System.Windows. Forms.DataGridV iew.ProcessKeyP review(Message& m)
              at System.Windows. Forms.Control.P rocessKeyPrevie w(Message& m)
              at System.Windows. Forms.Control.P rocessKeyMessag e(Message& m)
              at System.Windows. Forms.ComboBox. ChildWndProc(Me ssage& m)
              at
              System.Windows. Forms.ComboBox. ComboBoxChildNa tiveWindow.WndP roc(Message& m)
              at System.Windows. Forms.NativeWin dow.DebuggableC allback(IntPtr hWnd,
              Int32 msg, IntPtr wparam, IntPtr lparam)
              at System.Windows. Forms.UnsafeNat iveMethods.Disp atchMessageW(MS G&
              msg)
              at
              ....


              Comment

              • Marc Gravell

                #8
                Re: Linq-SQL canonical editable datagridview sample code

                Sorry - I don't think I'm going to be able to debug that just from a
                stacktrace, and I'm not in a desparate hurry to pick through your full
                bespoke code... sorry again...

                Marc

                Comment

                • Andrus

                  #9
                  Re: Linq-SQL canonical editable datagridview sample code

                  Marc,

                  I discovered that this occurs when all following conditions are met:

                  1. DataGridView contains single row
                  2. DataGridViewCol umn column is DataGridViewCom boBoxColumn
                  3. EditMode is EditOnEnter

                  In this case pressing up arrow in new row does *not* call BindingList
                  RemoveItem() method.

                  Is this .NET bug ? Any idea how to fix it ?

                  Andrus.


                  Comment

                  • Andrus

                    #10
                    Re: Linq-SQL canonical editable datagridview sample code

                    Following code reproduces DataGridView crash on edit.
                    Press down arrow, up arrow, down arrow. Exception occurs.

                    Any idea how to fix ?

                    Andrus.

                    using System;
                    using System.Windows. Forms;
                    using System.Componen tModel;

                    class Supplier {
                    public string Id { get; set; }
                    }

                    class Form1 : Form {
                    [STAThread]
                    static void Main() {
                    Application.Run (new Form1());
                    }

                    public Form1() {
                    DataGridView grid = new DataGridView();
                    // if this line is commented out, all is OK:
                    grid.EditMode = DataGridViewEdi tMode.EditOnEnt er;
                    ComboBoxColumn comboBoxColumn = new ComboBoxColumn( );
                    ComboBoxCell ComboBoxCell = new ComboBoxCell();
                    comboBoxColumn. CellTemplate = ComboBoxCell;
                    grid.Columns.Ad d(comboBoxColum n);
                    BindingList<Sup plierl = new BindingList<Sup plier>();
                    l.Add(new Supplier());
                    grid.DataSource = l;
                    Controls.Add(gr id);
                    }

                    class ComboBoxColumn : DataGridViewCom boBoxColumn { }

                    class ComboBoxCell : DataGridViewCom boBoxCell {
                    public override Type EditType {
                    get {
                    return typeof(ComboBox EditingControl) ;
                    }
                    }

                    }

                    class ComboBoxEditing Control : ComboBox, IDataGridViewEd itingControl {
                    protected int rowIndex;
                    protected DataGridView dataGridView;
                    protected bool valueChanged = false;

                    protected override void OnTextChanged(E ventArgs e) {
                    base.OnTextChan ged(e);
                    NotifyDataGridV iewOfValueChang e();
                    }

                    protected virtual void NotifyDataGridV iewOfValueChang e() {
                    valueChanged = true;
                    if (dataGridView != null) {
                    dataGridView.No tifyCurrentCell Dirty(true);
                    }
                    }

                    public Cursor EditingPanelCur sor {
                    get {
                    return Cursors.IBeam;
                    }
                    }

                    public DataGridView EditingControlD ataGridView {
                    get {
                    return dataGridView;
                    }
                    set {
                    dataGridView = value;
                    }
                    }

                    public object EditingControlF ormattedValue {
                    set {
                    if (value.ToString () != Text) {
                    Text = value.ToString( );
                    NotifyDataGridV iewOfValueChang e();
                    }
                    }

                    get {
                    return Text;
                    }
                    }

                    public object
                    GetEditingContr olFormattedValu e(DataGridViewD ataErrorContext s
                    context) {
                    return Text;
                    }



                    public void PrepareEditingC ontrolForEdit(b ool selectAll) { }

                    public bool RepositionEditi ngControlOnValu eChange {
                    get {
                    return false;
                    }
                    }

                    public int EditingControlR owIndex {
                    get {
                    return rowIndex;
                    }

                    set {
                    rowIndex = value;
                    }
                    }

                    public void ApplyCellStyleT oEditingControl (DataGridViewCe llStyle
                    dataGridViewCel lStyle) {
                    DropDownStyle = ComboBoxStyle.D ropDown;
                    }

                    public bool EditingControlW antsInputKey(Ke ys keyData, bool
                    dataGridViewWan tsInputKey) {
                    return !dataGridViewWa ntsInputKey;
                    }

                    public bool EditingControlV alueChanged {

                    get {
                    return valueChanged;
                    }
                    set {
                    valueChanged = value;
                    }
                    }
                    }
                    }


                    Comment

                    • Marc Gravell

                      #11
                      Re: Linq-SQL canonical editable datagridview sample code

                      I will look later; I can't promise anything...

                      Comment

                      • Andrus

                        #12
                        Re: Linq-SQL canonical editable datagridview sample code

                        Marc,
                        >I will look later; I can't promise anything...
                        Thank you.

                        I noticed that if I comment out OnTextChanged() override, exception does not
                        occur.
                        However this code is from MSDN sample.

                        Andrus.




                        Comment

                        • Marc Gravell

                          #13
                          Re: Linq-SQL canonical editable datagridview sample code

                          Can you (briefly) remind me what the purpose of this custom column is?
                          I'm reaching the conclusion that (sample or not) trying to implement
                          this from scratch is going to be hard; can you not just modify the
                          behavior of the existing control? For example - if you just want to
                          support up/down keys etc:

                          class ComboBoxEditing Control : DataGridViewCom boBoxEditingCon trol
                          {
                          private void ChangeUpDown(bo ol up)
                          {
                          DataGridViewCel l cell =
                          EditingControlD ataGridView.Cur rentCell;
                          if (cell == null) return;

                          int row = cell.RowIndex, col = cell.ColumnInde x;
                          if (up) row--; else row++;
                          if (row >= 0 && row < EditingControlD ataGridView.Row Count
                          && EditingControlD ataGridView.End Edit())
                          {
                          cell = EditingControlD ataGridView.Row s[row].Cells[col];
                          EditingControlD ataGridView.Cur rentCell = cell;
                          }
                          }
                          public override bool EditingControlW antsInputKey(Ke ys keyData,
                          bool dataGridViewWan tsInputKey)
                          {
                          switch (keyData)
                          {
                          case Keys.Up:
                          BeginInvoke((Me thodInvoker)del egate {
                          ChangeUpDown(tr ue);
                          });
                          return true;
                          case Keys.Down:
                          BeginInvoke((Me thodInvoker)del egate {
                          ChangeUpDown(fa lse);
                          });
                          return true;
                          case Keys.Enter:
                          BeginInvoke((Me thodInvoker)del egate {
                          EditingControlD ataGridView.End Edit(); });
                          return true;
                          case Keys.Escape:
                          BeginInvoke((Me thodInvoker)del egate {
                          EditingControlD ataGridView.Can celEdit(); });
                          return true;
                          default:
                          return base.EditingCon trolWantsInputK ey(keyData,
                          dataGridViewWan tsInputKey);
                          }
                          }
                          }

                          Comment

                          • Andrus

                            #14
                            Re: Linq-SQL canonical editable datagridview sample code

                            Marc,
                            Can you (briefly) remind me what the purpose of this custom column is?
                            Custom column is used to host virtual foreign key ComboBox.
                            There may be 50000 customers in customer table. So customer name combobox
                            data source should be populated dynamically.

                            I use subclassed DataGridViewCom boBoxCell GetFormattedVal ue() event to
                            populate combobox datasource
                            on the fly by calling Combobox datasource bindinglist special
                            AddIfNotExists( )
                            method:

                            protected override object GetFormattedVal ue(object value, int rowIndex, ref
                            DataGridViewCel lStyle cellStyle,
                            TypeConverter valueTypeConver ter, TypeConverter formattedValueT ypeConverter,
                            DataGridViewDat aErrorContexts context) {

                            ComboBoxColumn comboBoxColumn = OwningColumn as ComboBoxColumn;

                            comboBoxColumn. PickList.AddIfN otExists(value) ;

                            return base.GetFormatt edValue(value, rowIndex, ref cellStyle,
                            valueTypeConver ter, formattedValueT ypeConverter, context);

                            Custom combobox column implementation is required to allow grid to
                            host this combobox.
                            I havent way any other method to allow enter customers by name in grid.
                            I'm reaching the conclusion that (sample or not) trying to implement
                            this from scratch is going to be hard;
                            Probably DataGridView does not call ICancelAddNew.E ndNew() method.
                            New is remains in uncommited state when AddNewCore() is called. AddNewCore()
                            throws Invalid Operation exception.
                            I think there must be simple one line fix which fixes this. Probably
                            something simple is missing or wrong in custom column implementation. Or is
                            it possible to call EndNew() method itself from this code ?
                            can you not just modify the behavior of the existing control?
                            Should I really add event hander to GetFormattedVal ue() method ? There are
                            also other methods which needs to be overridden.
                            Should I try to add event handlers into all places ? MSDN recomments
                            subclassing and overriding methods as preferred technique for this.
                            >For example - if you just want to
                            support up/down keys etc:
                            The goal is to allow enter data using foreign keys when lookup table is big
                            and
                            resides in server.

                            Andrus.



                            Comment

                            • Marc Gravell

                              #15
                              Re: Linq-SQL canonical editable datagridview sample code

                              Call me crazy, but a drop-down isn't the first choice I'd use for
                              this!

                              I don't know where the problem is; normally, EndNew/CancelNew are used
                              correctly, but in the code you posted RemoveItem indeed doesn't get
                              called. I dont' know why.

                              Comment

                              Working...