Forums
Forums are Read-Only. Use the new Support Center. To start a general discussion, use the General category when submitting your question.

Q252960 : update command sets all fields

Last post 1/3/2012 3:39 AM by Uriah (DevExpress Support). 40 replies.
Support Center Article: Q252960
1 2 3 Next
Sort Posts: Previous Next
  • Michael Proctor [DX-Squad]

    Q252960 : update command sets all fields

    3/25/2010 7:58 AM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321
    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 11:18 AM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     You are the Man Michael!!!

    Thank you!!

  • Ralph Rutschmann

    Re: Q252960 : update command sets all fields

    3/25/2010 2:26 PM
    • Top 75 Contributor
    • Joined on 12/14/2007
    • Posts 281

     Hi Michael,

    coooool! Smile

    Great work, thank you for sharing this!

    Of course, this should work of the box, any other makes not really sense. But XPO rules, and we can do it by ourselves. With a little help from Michael... Big Smile

    Best regards, Ralph

  • Trevor Westerdahl

    Re: Q252960 : update command sets all fields

    3/25/2010 3:25 PM
    • Top 25 Contributor
    • Joined on 5/4/2007
    • Portland, Oregon
    • Posts 2,424
    Nice work. I also agree that should be the default behavior "out-of-the-box". Maybe they (DevExpress) should consider implementing it (with your permission of course).
     
    Trevor
    "Ralph Rutschmann" wrote in message news:299181@community.devexpress.com...

     Hi Michael,

    coooool! Smile

    Great work, thank you for sharing this!

    Of course, this should work of the box, any other makes not really sense. But XPO rules, and we can do it by ourselves. With a little help from Michael... Big Smile

    Best regards, Ralph



    http://community.devexpress.com/forums/p/87479/299181.aspx#299181

    Trevor Westerdahl - DX Squad
    BLOG: http://trevorunlocked.blogspot.com/
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 3:57 PM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     Hey Michael,

    never had any problems with aliased fields? For example:

    [Persistent("CreatedBy")]
    private User _CreatedBy;

    [PersistentAlias("_CreatedBy")]
    public User CreatedBy
    {
    get
    {
    return this._CreatedBy;
    }
    }

    How do you handle such properties in your solution? Do you manually call Onchanged("_CreatedBy") or OnChanged("CreatedBy")?

  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 6:04 PM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    Martin Praxmarer:

     Hey Michael,

    never had any problems with aliased fields? For example:

    [Persistent("CreatedBy")]
    private User _CreatedBy;

    [PersistentAlias("_CreatedBy")]
    public User CreatedBy
    {
    get
    {
    return this._CreatedBy;
    }
    }

    How do you handle such properties in your solution? Do you manually call Onchanged("_CreatedBy") or OnChanged("CreatedBy")?

    You will see that the code calls the XPClassInfo.GetPersistentMembers method which pulls the only the persisted members out of the class.

    So in your example we wouldn't see the CreatedBy (Member) we would only see the _CreatedBy (Member) which will be persisted to CreatedBy (Field)

    I use PersistentAlias's everywhere.

    For your "stored" readonly fields, I always use the SetPropertyValue method of PersistentBase this calls the OnChanged() method

    SetPropertyValue("_CreatedBy", _CreatedBy, User) 

    Hope this helps

     

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 6:09 PM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     Hi Michael,

    yes - of course the persistent members collection will return _CreatedBy as persistent field - but in my code currently i just use

    this._CreatedOn = DateTime.Now;
    this._CreatedBy = Session.GetObjectByKey<User>(SecuritySystem.CurrentUserId); 

    nothing more - so i think i will probably need to refactor these places...

  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 6:15 PM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    Ahh.. I see, that certainly isn't XPO Best Practice, you should always be using the SetPropertyValue for field setters that way it ensures you are calling the OnChanged event.

    This would rectify your issue.

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 6:26 PM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     Your are right michael,

    i didnt call it here because they are service fields - and since it was no problem yet because xpo always saved them it was ok for me. where im not sure currently is if i should call OnChanged for the public property or the private member. I you look at the XAF Resources.cs they do:

    [Persistent("Color")]
      private Int32 color;

    [NonPersistent]
      public Color Color {
       get { return Color.FromArgb(color); }
       set {
        color = value.ToArgb();
        OnChanged("Color");
       }
      }

    So they notify about the public field - which makes sense to me since this property is bound to the UI - so i think i probably change the OnChanged method and get the PersistentAlias Attribute to get the member - i think that would be the best way!

  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 7:49 PM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    Spot on Martin,

    You do need to call the OnChanged() for your public member.

    So with your SetPropertyValue you can specify the OnChanged propertyname

    so in your first example do (EDIT: had the values wrong way around Surprise)

    SetPropertyValue("CreatedOn", _CreatedOn, DateTime.Now);

    SetPropertyValue("CreatedBy", _CreatedBy, Session.GetObjectByKey<User>(SecuritySystem.CurrentUserId));

    This will set your "persisted" valueholders _<name> and provide the "OnChanged" for your Public readonly properties <name>

    Also the reason we do the SetPropertyValue("OnChangedPropertyName", valueHolder, newvalue) instead of SetPropertyValue("TheActualProperty", newValue) is because the latter has to use reflection to find the valueholder to store the new field which will incur a performance hit.

    Hope this helps

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/25/2010 7:53 PM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    While we are on the subject, you got me started now Big Smile

    Same thing applies to calculated fields, within any of the properties setters that affect a calculated fields outcome you need to call the OnChanged("CalculatedField") from the setter of the "source" property, for example

            Private _costPrice As Double
            Public Property CostPrice As Double
                Get
                    Return _costPrice
                End Get
                Set(ByVal Value As Double)
                    SetPropertyValue("CostPrice", _costPrice, Value)
                    If Not IsLoading Then
                        OnChanged("GrossProfit")
                    End If
                End Set
            End Property

            Private _sellPrice As Double
            Public Property SellPrice As Double
                Get
                    Return _sellPrice
                End Get
                Set(ByVal Value As Double)
                    SetPropertyValue("SellPrice", _sellPrice, Value)
                    If Not IsLoading Then
                        OnChanged("GrossProfit")
                    End If
                End Set
            End Property

            <PersistentAlias("SellPrice - CostPrice")> _
            Public ReadOnly Property GrossProfit As Double
                Get
                    Return SellPrice - CostPrice
                End Get
            End Property

     

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/26/2010 3:55 AM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     Hi Michael,

    nice discussion :)

    SetPropertyValue("CreatedBy", _CreatedBy, DateTime.Now); - this makes sense to me - notify about the public member - but then your code on the baseobjects OnChanged method is not quite correct i think? because then you notify about the public member which is actual not found in the persistentmembers. Your example with GrossProfit isnt clear to me - GrossProfit is not stored in the DB in this case - so no need about notification?

    <Persistent> _
            Public ReadOnly Property GrossProfit As Double
                Get
                    Return SellPrice - CostPrice
                End Get
            End Property

    If it would look like this it make sense to call OnChanged("GrossProfit"). The property below is also a dangerous part

     

             [Persistent]
            [Size(25)]
            public string ContactKindInfo
            {
                get
                {
                    string infostring = String.Empty;
                    if (!this.IsLoading && this.LinkedContactKinds.Count > 0)
                    {
                        foreach (ContactKind item in this.LinkedContactKinds)
                        {
                            infostring += String.Format("{0} ", item.Name.Substring(0, 1));
                        }
                    }

                    return infostring; ;
                }
            }

    Its hard to notify about that property. So i think i will do

    if ((m.IsPublic && m.IsReadOnly) || m is ServiceField || ((ISupportChangedMembers)theObject).ChangedMembers.Contains(m))
    {

    always save if m.IsPublic && m.IsReadOnly - i will do some testings and notify you about the results!

  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/26/2010 4:36 AM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    Umm good pickup Martin ;)

     

    In my app I have been doing

    SetPropertyValue("_createdOn", _CreatedOn, DateTime.Now)
    OnChanged("CreatedOn")

    before this discussion I thought the first parameter of the SetPropertyValue actually required the "name" of the member you were setting (as I thought XPO was using Reflection to find the member), it was only during this discussion that I thought about it more and realised that if indeed XPO is using Reflection to pull up the member that would have to be woefully slow, it was then that I realised the "string" propertyname was just used for the "OnChanged' part, hence I mentioned you could just have that for your notification (without giving it much more thought)

    you are however right and the previous way I have done it would be "valid" in what we are doing in the OnChanged to do update tracking.

     

    In regard to the GrossProfit and why to call OnChanged, the reason here is Binding, Binding updates on property changes so the issue is if you change a "source" property such as cost or sell you won't see it reflected in your control that is bound to grossprofit as the "bindingmanager thingy" hasn't been told there was a change to GrossProfit. So this is more for a fully compatable object that will work as expected when bound.

    From memory I think XAF has some "ImmediatePost" or something that I believe does something like this also but I would still put the OnChanged("GrossProfit") in both CostPrice and SellPrice.

    With your example of ContactKindInfo I do something a little "different" here, I only update this field when the child object changes something that would "affect' my parent object.

    So I will assume your Parent Class in your example is Contact and the Children are ContactKind

    In the Contact constructor I place

     addhandler LinkedContactKinds.CollectionChanged, AddressOf LinkedContactKinds_CollectionChanged

    and in the Finalize event of the object I place

    removehandler LinkedContactKinds.CollectionChanged, AddressOf LinkedContactKinds_CollectionChanged

    my method that handles the event looks like

             Private Sub LinkedContactKinds_CollectionChanged(ByVal sender As Object, ByVal e As XPCollectionChangedEventArgs)
                If e.CollectionChangedType = XPCollectionChangedType.AfterAdd Or e.CollectionChangedType = XPCollectionChangedType.AfterRemove Then
                    UpdateContactKinds()
                End If
            End Sub

    then in my ContactKind class I would have like in your case the Name property affects your "Parent" class so in the Name Property I would have

    If not IsLoading() and Contact IsNot Nothing then
        Contact.UpdateContactKinds()
    end if

    then all I would have in your Contact class

    <persistent()> _
    <Size(25)> _
    private _contactKindInfo as String

    Public ReadOnly Property ContactKindInfo as String
        Get
            return _contactKindInfo
        End Get
    End Property

    Public Sub UpdateContactKindInfo()
                    dim infostring as string = String.Empty
                    if LinkedContactKinds.Count > 0)
                        for each item as ContactKind in LinkedContactKinds
                            infostring &= String.Format("{0} ", item.Name.Substring(0, 1))
                        next
                    end if
                    SetPropertyValue("_contactKindInfo", _contactKindInfo, infostring)
    End Sub

     

    So with that basically if something changes your "ContactKindInfo" will be "updated", but in general will be "left" alone. and because the OnChanged still occurs it is safe.

    Just some food for thought

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
  • Martin Praxmarer [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/26/2010 5:41 AM
    • Top 50 Contributor
    • Joined on 3/16/2009
    • Tirol, Austria
    • Posts 546

     Hi Michael,

    good point about the ContactKindInfo - i will change my property in this case. About the SetPropertyValue("CreatedOn", _CreatedOn, DateTime.Now) - i have changed the BaseObject OnChanged method now, to get the correct member:

    if (!this.IsLoading)
                {
                    XPMemberInfo member = this.GetPersistentMember(propertyName);
                    if (member != null && !this.ChangedMembers.Contains(member))
                    {
                        this.ChangedMembers.Add(this.ClassInfo.GetMember(member.Name));
                    }
                }

    private XPMemberInfo GetPersistentMember(string propertyName)
            {
                XPMemberInfo persistentMember = this.ClassInfo.GetPersistentMember(propertyName);
                if (persistentMember == null)
                {
                    var memberInfo = this.ClassInfo.FindMember(propertyName);
                    if (memberInfo != null && memberInfo.IsAliased)
                    {
                        PersistentAliasAttribute pa = (PersistentAliasAttribute)memberInfo.GetAttributeInfo(typeof(PersistentAliasAttribute));
                        CriteriaOperator criteria = CriteriaOperator.Parse(pa.AliasExpression);
                        if (criteria is OperandProperty)
                        {
                            string[ path = ((OperandProperty)criteria).PropertyName.Split('.');
                            memberInfo = null;
                            foreach (string pn in path)
                            {
                                if (memberInfo == null)
                                    memberInfo = this.ClassInfo.GetMember(pn);
                                else
                                    memberInfo = memberInfo.ReferenceType.GetMember(pn);
                            }

                            return memberInfo;
                        }
                    }
                }

                return persistentMember;
            }

    So if we notify about the public member - it is not found in the persistentmember - i i look if it is aliased and get the aliased member.

  • Michael Proctor [DX-Squad]

    Re: Q252960 : update command sets all fields

    3/26/2010 5:57 AM
    • Top 25 Contributor
    • Joined on 6/21/2007
    • Cairns, QLD, Australia
    • Posts 1,321

    Martin,

    Sweet as! Love the Attribute checking to resolve the Persisted field, nice work. I knew there was a reason I posted all this here ;)

    Thanks mate

    Regards,

    Michael Proctor [DX-Squad]

    Find your answer quicker DX Search http://search.devexpress.com
    VB.NET FTW
    Blog: alfware.com.au
    Twitter: @aussiealf
    Skype: expandsoftware
    MSN: michael (nospamat) expandsoftware.com.au
    EvE Online: Aussie ALF
1 2 3 Next
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.