CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Forum has moved

New location: CSLA .NET forum


CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • Hiding properties in datagrid

    rated by 0 users
    Answered (Verified) This post has 1 verified answer | 13 Replies | 1 Follower

    Top 500 Contributor
    22 Posts
    TygreWolf posted on Tue, Jun 25 2013 9:52 AM

    Hello,

    I have a simple WPF application using CSLA 4.5.30, with a DataGrid bound to a CollectionViewSource, which in turn is bound to a ViewModel that inherits from a CSLA ViewModel<T> object.  In my case, it's a UserList (CSLA style) containing UserInfo objects.

    The data grid by default has the AutoGenerateColumns property set to true.  When displayed, it shows both the IsBusy and IsSelfBusy properties of the Model, along with the data associated with the UserInfo object.

    Why are the IsBusy and IsSelfBusy properties exposed as columns on the data grid, and what is the best way to make sure they are hidden?

    -Jason

    Answered (Verified) Verified Answer

    Top 500 Contributor
    22 Posts
    Verified by TygreWolf

    So based on the post found here, WPF doesn't support data annotations.

    That being the case, I added code in the code-behind (something I hate doing) that takes care of both the displaying of extra columns, and the column header naming issue:

    private void DgUsers_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
            {
                var pd = (PropertyDescriptor)e.PropertyDescriptor;
                var da = (DisplayAttribute) pd.Attributes[typeof (DisplayAttribute)];

                if (da == nullreturn;
                
                var autoGenerateField = da.GetAutoGenerateField();
                if (autoGenerateField != null && !autoGenerateField.Value)
                {
                    e.Cancel = true;
                }

                if (!string.IsNullOrEmpty(da.Name))
                {
                    e.Column.Header = da.Name;
                }
            }

    It's not the most elegant solution, since I'd rather have everything hooked up via data binding and defined in the XAML, rather than writing code-behind, but it works.  I'm not sure if there's another possible solution, or if WPF will support the data annotations in the future.

    -Jason

    All Replies

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Tue, Jun 25 2013 10:37 AM

    Hi, 

    It is a balance between hiding values from databinding and expose them for databinding so that you can f.ex bind the enabled value of a button to IsDirty.

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    22 Posts

    So other than turning off AutoGenerateColumns and manually defining each column in the XAML, is there any other (read: better) way to hide those two properties?

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Tue, Jun 25 2013 11:07 AM

    Do you use your own intermediate base classes?

    In the Csla.Core.BusinessBase class the IsBusy, IsSelfBusy, IsDirty etc all have:

        [Browsable(false)]
        [Display(AutoGenerateField = false)]

    attributes attached to them so none of them should show up by default in DataGrid.

    And this has been unchanged for more than a year.

     

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    22 Posts

    No, I don't.

    I have

    public
     sealed class UserListViewModel : ViewModel<Library.BusinessObjects.Users.UserList>

    The UserList inherits directly from  ReadOnlyListBase<UserListUserInfo>

    And the XAML

    <
    UserControl.Resources>
        <vm:UserListViewModel x:Key="UserListViewModel"/>
        <CollectionViewSource x:Key="UserListModelViewSource" Source="{Binding Path=Model, Source={StaticResource UserListViewModel}}"/>
    </UserControl.Resources>
    <DataGrid x:Name="DgUsers" ItemsSource="{Binding Source={StaticResource UserListModelViewSource}}"/>

    This displays a data grid that, as far as I can see, has 2 issues.  The first, is that IsBusy and IsSelfBusy are displayed as columns in the grid.  The second is that the column headers do not match what is defined in my UserInfo class (whether I use FriendlyName in the RegisterProperty constructor, or just use the Display attribute).

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Tue, Jun 25 2013 11:48 AM

    Can you verify that the base class for UserInfo has:

        /// <summary>
        /// Gets a value indicating whether this
        /// object or any of its child objects are
        /// running an async operation.
        /// </summary>
        [Browsable(false)]
        [Display(AutoGenerateField = false)]
        public virtual bool IsBusy
        {
          get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }
        }
    
        /// <summary>
        /// Gets a value indicating whether this
        /// object is
        /// running an async operation.
        /// </summary>
        [Browsable(false)]
        [Display(AutoGenerateField = false)]
        public virtual bool IsSelfBusy
        {
          get { return _isBusy || LoadManager.IsLoading; }
        }

    and that these properties is not overriden in your UserInfo class.

    Which DataGrid do you use?

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Tue, Jun 25 2013 11:56 AM

    Or maybe it's just the Microsoft DataGrid does not check AutogenerateField = false on the Display attribute.

    http://social.msdn.microsoft.com/Forums/vstudio/en-US/825b9300-5479-41d8-8c6c-30cfeb226c6e/hide-column-inside-a-wpf-datagrid

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    22 Posts

    I can't validate the code of the base class.  The CSLA reference I'm using is downloaded from NuGet.  I can tell you that it's version 4.5.30.0.  Also, my UserInfo class does not override either of those properties.

    All in all, these are pretty simplistic classes.  I'm not really sure how the DataGrid performs the data binding under the hood, so it's quite possible that it's ignoring certain aspects of the binding and/or CSLA framework.

    Then again, it could just be something stupid that I'm doing (or not doing).

    I've put together a sample solution that shows this behavior.  It's a VS2012 solution.  The file is Sample.zip and can be found at http://www.fileswap.com/dl/PgVg7YriLE/.

    -Jason

    Top 500 Contributor
    22 Posts

    Just an FYI, I've also tried adjusting the XAML to:

    <
    DataGrid x:Name="DgUsers" AutoGenerateColumns="False" ItemsSource="{Binding Source={StaticResource UserListModelViewSource}}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=UserId}" Header="{Binding Source=UserIdProperty, Path=FriendlyName}"/>
            <DataGridTextColumn Binding="{Binding Path=FirstName}" Header="{Binding Source=FirstNameProperty, Path=FriendlyName}"/>
            <DataGridTextColumn Binding="{Binding Path=LastName}" Header="{Binding Source=LastNameProperty, Path=FriendlyName}"/>
        </DataGrid.Columns>
    </DataGrid>

    This successfully limits what columns are shown on the data grid, thereby keeping IsBusy and IsSelfBusy from being displayed, but the binding to the Header property from the friendly name does not work.  Having to define the columns individually is not an ideal solution, and having to define the display name of the column header by static text (Header = "User ID") is an even less ideal solution.

    Top 100 Contributor
    80 Posts

    I typically have a root object that hosts my list object, so the binding would be Model.MyList.  By doing this only the items on the list show up and I can use auto generated columns.

    Top 500 Contributor
    22 Posts

    Understood, but I don't think that type of redundancy should be necessary.  It would actually take less code just to define the columns in the XAML.  It also doesn't solve the column naming/friendly name/display attribute  issue.

    -Jason

    Top 500 Contributor
    22 Posts
    Verified by TygreWolf

    So based on the post found here, WPF doesn't support data annotations.

    That being the case, I added code in the code-behind (something I hate doing) that takes care of both the displaying of extra columns, and the column header naming issue:

    private void DgUsers_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
            {
                var pd = (PropertyDescriptor)e.PropertyDescriptor;
                var da = (DisplayAttribute) pd.Attributes[typeof (DisplayAttribute)];

                if (da == nullreturn;
                
                var autoGenerateField = da.GetAutoGenerateField();
                if (autoGenerateField != null && !autoGenerateField.Value)
                {
                    e.Cancel = true;
                }

                if (!string.IsNullOrEmpty(da.Name))
                {
                    e.Column.Header = da.Name;
                }
            }

    It's not the most elegant solution, since I'd rather have everything hooked up via data binding and defined in the XAML, rather than writing code-behind, but it works.  I'm not sure if there's another possible solution, or if WPF will support the data annotations in the future.

    -Jason

    Top 10 Contributor
    2,279 Posts

    Well, you could create your own subclassed DataGrid with your desired behavior and thus not require codebehind in your View.

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    22 Posts

    Yes Jason likes this post.

    Perhaps in the future.  It'd be nice to have some automated grouping functionality, as well.  For now, I'll stick with the basic requirements my application needs to perform its intended duty.

    -Jason

    Page 1 of 1 (14 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems