Tech in the 603, The Granite State Hacker

What’s New in C# 7 (CSharp)

Thanks again to folks who joined in for the presentation at the Granite State Windows Platform App Devs  (@WPDevNH) at the Microsoft Store in Salem, NH last night.

Meetup:
https://www.meetup.com/Granite-State-NH-WPDev/events/238684720/

The site most of the content came from was MSDN:



Here’s the slide deck:

and example code on GitHub:
https://github.com/GraniteStateHacker/WPDevNH_CSharp7

Tech in the 603, The Granite State Hacker

Back To Where We Belong

Big changes for me lately, so more of a narrative personal post than a technical presentation…  and with apologies. I’ve been too wrapped up with the finer details of finishing up my project with Fidelity to get any blog posts out at all since November last year (yikes). 

I’ll get back to the regularly scheduled broadcast shortly.

About this time two years ago, I started a project with a financial firm out in Back Bay, in the John Hancock tower.  We rolled out SharePoint 2013 on-prem, and migrated it from multiple legacy farms… both of which were WSS3.0.   So between the build out and migration, I ended up on that project for a solid three months or so.  Not a bad gig, but… Boston commute (thank God for the Boston Express Bus), and no C# (not even ASP.NET).  It was really more of an IT Pro gig than development.  I was able to do some really fancy powershell stuff to manage the migration, but definitely not my first choice.

That fall, I landed a role on Fidelity’s new order management/trading desktop build-out. I have to say, that was roughly the kind of project I’ve been angling for, for years.  

Technology-wise, the only thing that could have made it any better was to be Windows 10/UWP based, maybe with mobile tendencies.  Alas, building rich clients of any sort is relatively rare, so .NET 4.6 is better than… not .NET at all. 

Still… All C#/WPF, desktop client…   

A good number of my most recent technical posts and presentations were heavily influenced by this project.   Sure, Boston again… for a good portion of it… but they let me work at Fidelity’s Merrimack location for a good chunk of the latter half of the project, too.

And it was maybe the longest running single version project I’ve been on in my life.  I was on it for 18 months…  a full three times longer than a “big” six month project.

All that to say I haven’t spent a full, regular day at a desk at BlueMetal Boston’s Watertown office in just about two full years. 

In that time, I’ve seen too many great teammates move on, and about as many new teammates join us.  We were employee owned back then, and I rode out the entire Insight purchase while “living” at the clients’ site.

Still, one thing that bothered me is a pattern I don’t intend to continue repeating.  When I took my position at Jornata that became BlueMetal, I accepted the title of Senior Developer, even though it appeared to be a step down from my Systems Architect title at Edgewater. 

My reason for accepting that was primarily that I was joining Jornata as a SharePoint make/break, and I needed to get a little more SharePoint experience under my belt before I was comfortable calling myself a SharePoint Solutions Architect.   By the time the BlueMetal merger worked itself around, I realized my options had opened broadly.  I got the SharePoint experience I needed, but it became very apparent that it wasn’t the experience I wanted.  Unfortunately, I was stuck with the “Senior Developer” title even on projects where my depth of experience went much deeper. 

SharePoint is cool for using, and even integrating, and IT Pros get a lot of mileage out of it, but as for software developers… well…  let’s just say I let SharePoint fuck up my career enough that I had to re-earn my “Architect” title.  (pardon my language, there’s no better word for it.)  I always deliver a win, but I’m a Visual Studio kinda guy.  I’m still happy to develop integrations with SharePoint, and support the SharePoint community… but while there’ve been major improvements in the past few months alone, Microsoft has been muddling it’s SharePoint developer story for years, and I let myself fall victim to it.

Thankfully, the Fidelity project did the trick…  it was just the level of high-touch, real Enterprise application development that I needed to earn my self respect back, and prove out my abilities in the context of BlueMetal. 

I’ll admit, while I feel this is restoring my title, it is certainly not lost on me that “Architect” at BlueMetal is a class (or two) above “Architect” in any of my previous companies.  I always felt I was there, even if I felt discouraged and unsupported by my former teams.  I am truly honored to be among those who’ve earned this title in this company, and very appreciative of the recognition.

At BlueMetal, I’m supported and inspired by my team, and really seeing this as validation that my career vector is now fully recalibrated.

I’ve said this before: meteorologists are very well educated with lots of fancy tools to help them be more accurate, but reality is that unless you’re standing in it, you don’t really have much hope of getting it truly right.  I have no intention of becoming a weatherman architect.  Hands-on the code is where my strength (and value) is, so that’s where I’ll always shoot to be.

Tech in the 603, The Granite State Hacker

Need to Synchronize Columns of a Master/Detail Grid in DevEx WPF?

I generally prefer Telerik controls, but I’ve got a client that uses Developer Express.  I recently had a need to synchronize columns in a Developer Express WPF Master/Detail grid.   It’s a bit of an unusual circumstance, where we have Master / Detail records that use the same view interface, but found the TreeListControl unable to scale up to the demands of our use cases.  The client still wanted the detail grid’s columns to appear to functionally be the same column as the master record’s (with the ability to show/hide the detail).

Thankfully, the Dev Express GridColumn class is a DependencyObject, and all the needed properties are exposed as DependencyProperty’s.

Since the detail grid has the same data interface as the master grid, I was even able to clone the column definitions. 

Finally, since this was an MVVM project, I didn’t want the functionality in code-behind, so I abstracted the code for this into a Behavior.

The approach was to bind the Width, Visibility, and VisibleIndex properties of each master grid column to a cloned detail grid column, giving the two entities the appearance of being one functional entity.
Here’s the snippet representing the detail grid definition….



        <dxg:GridControl>

          <dxg:GridControl.DetailDescriptor>


                <dxg:DataControlDetailDescriptor ItemsSourceBinding="{Binding Details}">


                    <dxg:GridControl x:Name="DetailsGrid" AutoGenerateColumns="None" ColumnsSource="{StaticResource ColumnsCollection}" >


                        <dxg:GridControl.View    >




                            <dxg:TableView  AutoWidth="False"


                            AllowCascadeUpdate="False"


                            AllowFixedGroups="True"

                            ShowGroupPanel="False"

                            CellStyle="{StaticResourceDefaultCellStyle}"

                            NavigationStyle="Row"

                            ShowGroupedColumns="True"

                            AllowGrouping="True"

                            AllowEditing="False"

                            AllowScrollAnimation="False"

                            ShowFixedTotalSummary="False"

                            AllowHorizontalScrollingVirtualization="True"

                            HorizontalScrollbarVisibility="Auto"

                            RowStyle="{StaticResource RowStyle}"

                            AlternateRowBackground="{x:Static dxRes:DevExpressResources.AlternateRowBackgroundBrush}"

                            UseLightweightTemplates="None"

                            ShowColumnHeaders="False"

                               />

                        </dxg:GridControl.View>

                        <i:Interaction.Behaviors>


                            <local:SyncDetailGridColumnsBehavior/>


                        </i:Interaction.Behaviors>

                    </dxg:GridControl>

                </dxg:DataControlDetailDescriptor>

            </dxg:GridControl.DetailDescriptor>

        </dxg:GridControl>



Note the highlighted part above that introduces a local class called SyncDetailGridColumsBehavior, shown in its entirety below:

using System.Windows.Data;

using System.Windows.Interactivity;

using DevExpress.Xpf.Grid;


namespace Local
{
    public class SyncDetailGridColumnsBehavior : Behavior<GridControl>
    {
        private GridColumnCollection_parentGridColumns;
        private GridColumnCollection_detailsGridColumns;
        protected override void OnAttached()
        {
            _detailsGridColumns = AssociatedObject.Columns;
            _parentGridColumns = AssociatedObject.ResolveParentColumnCollection();
            InitializeMasterDetailGrid();
        }
       
        private void InitializeMasterDetailGrid()
        {
            _detailsGridColumns.CloneColumnsAndBindWidthsFrom(_parentGridColumns);
        }
    }
    internal static class ColumnHelpers
    {
        public static GridColumnCollectionResolveParentColumnCollection(this GridControl associatedObject)
        {
            var result =
                ((DevExpress.Xpf.Grid.GridControl)
                    ((System.Windows.FrameworkContentElement) associatedObject.Parent).Parent).Columns;
            return result;
        }
        public static voidCloneColumnsAndBindWidthsFrom(this GridColumnCollection targetGridColumns,
            GridColumnCollection sourceGrid)
        {
            targetGridColumns.Clear();
            foreach (var aSourceColumn in sourceGrid)
            {
                var aClonedColumn = aSourceColumn.Clone();
                aSourceColumn.BindWidths(aClonedColumn);
                aSourceColumn.BindPositions(aClonedColumn);
                targetGridColumns.Add(aClonedColumn);
            }
        }
        public static GridColumn Clone(this GridColumn source)
        {
            return new GridColumn()
            {
                Name = source.Name,
                Width = source.Width,
                Binding = source.Binding,
                Header = source.Header,
                Style = source.Style,
                CellStyle = source.CellStyle,
                CellTemplateSelector = source.CellTemplateSelector,
                CellTemplate = source.CellTemplate,
               
            };
        }
        public static void BindWidths(this GridColumn source, GridColumn bindingPartner)
        {
            source.SetBinding(BaseColumn.WidthProperty,
                new Binding(“ActualWidth”)
                {
                    Source = bindingPartner,
                    Mode = BindingMode.OneWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                });
            bindingPartner.SetBinding(BaseColumn.WidthProperty,
                new Binding(“ActualWidth”)
                {
                    Source = source,
                    Mode = BindingMode.OneWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                });
        }
        public static void BindPositions(this GridColumn source, GridColumn bindingPartner)
        {
            source.SetBinding(BaseColumn.VisibleIndexProperty,
                new Binding(“VisibleIndex”)
                {
                    Source = bindingPartner,
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                });
           
        }
        public static void BindVisibility(this GridColumn source, GridColumn bindingPartner)
        {
            source.SetBinding(BaseColumn.VisibleProperty,
                new Binding(“Visible”)
                {
                    Source = bindingPartner,
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                });
        }
    }
}
       

I expect this to cover 90% of our needs, the other 10% has to do with row selection across master/detail boundaries, but that’s a story for another day.

In the meantime, let me know how this makes ya feel…  leave a comment, below.

Thanks!

Tech in the 603, The Granite State Hacker

Tribute to the TI 80-something Graphing Calculators

Rummaging thru a box of stuff in storage, I ran across my old Texas Instruments TI-85 calculator.  I had to stop and fiddle it for a moment. I grabbed some AAA batteries, only to discover that the CR1616 backup had given up… the calculator operates like new, as in factor reset… but sadly, that means a game program I wrote for it 20 years ago was finally gone forever.

Back in the early 90’s, Exeter Area High School had an advanced math course that required a TI-81 calculator. I gladly used the course as an excuse to get my hands on this relatively expensive (near $100 in 1990 dollars) but amazing piece of hardware at the time.

In short order, I added its programming language to the list of languages I had already taught myself.  I loved using trigonometric functions to create pictures. I used to program it to do my trig and pre-calc homework for me. (In retrospect, my attempt at “cheating” was a hack that I learned more from than any lecture or textbook ever would teach me… you see, in order to program the calculator to do advanced math for me, I had to thoroughly understand it, myself.)

My own TI-85, which I upgraded to
for calculus at UNH. It’s a bit dusty today.
It cost about $100 when I
purchased it in the early 90’s.

The TI-8x calculators were my “gateway drug” to my love of mobile development.  I was already developing software for PCs, but I loved the challenges imposed by yet more limited footprints and hardware capabilities. 

I kept my TI with me to the point that my sister nicknamed it a “porta-geek”…  (There was even a girl who stole it from me, thinking to wound me for the fact that I wasn’t interested in dating her. It had no effect; I obliviously assumed I’d misplaced it in my own absent-mindedness. The story came out several years later, after I’d purchased a replacement.)

The term “porta-geek” is a term I still whimsically apply on occasion to my current daily driver mobile device, my Lumia 950XL running Windows 10.  My sister’s jibe didn’t phase me, either.

By coincidence, I was also in Target’s electronics department today. I was surprised to notice that they still had several 20+ year old TI-80-somethings…  but rather than the price being lower, the prices are actually higher.

A selection of same-generation TI calculators at Target today (3/20/2016).  Notice the TI-80-somethings still going for about $100+.

I can’t really say why 20+ year old calculators should still cost more than they originally did…  clearly normal technology market forces are not in effect for them.  My spidey-sense for socialistic-driven monopoly tingles.  I’m not the only one to have noticed the… discrepancy… over the past couple decades.  ( https://www.quora.com/Why-does-a-TI-83+-calculator-cost-the-same-as-it-did-12-years-ago )

That said, they were, and are great devices.

I’d love to see a Windows 10 emulator app made out of them….  maybe some day I’ll find enough spare time…  🙂

Tech in the 603, The Granite State Hacker

An Alternative Profile, in C#

The folks at BlueMetal keep profiles of each team member on the web site.  They asked all of the recently added teammates to draft up a profile. The hard part for me was that it felt like I needed to model and express myself in terms of… C#, of course.  🙂   I wrote this with enough supporting scaffolding to get it to compile…

using System;
using System.Threading;
using System.Threading.Tasks;
using BlueMetal;
using Microsoft;
using Database.SQL;
using Web;
using Mobile;
using Services;
using Cloud;
using Experience;
namespace Profile
{
   public class Jim_Wilcox : SeniorApplicationDeveloper
   {
     private Jim_Wilcox()
       : base()
     {
       Blog = http://granitestatehacker.kataire.com&#8221;;
       CommunityLeader =
         Community.NH_SharePoint_UsersGroup |
         Community.NH_WindowsPlatformApplicationDevelopers_UsersGroup;
       EventCoOrganizer = Community.SharePointSaturday_NH;
       YearsOfExperience = Qualifications.Decades;
       Vision = Qualifications.EnterpriseLevel;
       LearningMode =
           Qualifications.Continuous | Qualifications.EarlyBinding;
       Skills =
           Skill.NET | Skill.MVC | Skill.SharePoint | Skill.TFS |
           Skill.Azure | Skill.SQL | Skill.Many_More;
       Industries =
           new System.Collections.Generic.List<Industry>() {
             Industry.Military, Industry.Telecommunications ,
             Industry.Retail, Industry.Financial ,
             Industry.Healthcare, Industry.Hospitality ,
             Industry.Concierge, Industry.Construction ,
             Industry.Many_More};
     }
     public static async Task EngageAsync(StatementOfWork context)
     {
       await BlueMetal.Project.Execute(context).UsingDeveloper(Individual);
     }

     public static Jim_Wilcox Individual{ get { _unique = _unique ?? new Jim_Wilcox(); return _unique; } }

     }
}

Tech in the 603, The Granite State Hacker

Keeping in the Code

At the end of the day, the business solution is always the most important part of the equation, but it’s not the only part.  While I’m working on a solution, I’m also looking at tools, scaffolding, and framework.  This is especially true if others are going to be working on the project, and that accounts for nearly every non-trivial project.

How easy is it to set up?  How easy is it to work with?  Do the expressions make sense?  Can I hand it off to my least experienced teammate, get them to pick this up, and expect reasonable results?  (For that matter, can I hand it off to my most experienced teammate and expect them to respect the design decisions I made? )

Keeping my head in the code is critical.  Loosing touch with tools means shooting in the dark on the above questions.  It doesn’t matter what their experience is, if you ask someone to push a tack into a corkboard, hand them the wrong tools for the job, they won’t be able to push the thumbtack into the corkboard… or you’ll nuke your budget paying for tools that are overpowered for the job.  (But that thumbtack will be SO IN THERE!)

In any case, in most projects, after the architecture & technical designs have been sorted out, frameworks, built, automations put in place, I’ll take on the coding, too.

Of course, I’ve said this before…  if you can really simplify the work, what’s to stop you from taking the extra step and automating it?   I’m always eyeing code, especially “formulaic”, repetititive stuff, looking for opportunities to simplify, abstract, and/or automate.

Tech in the 603, The Granite State Hacker

If It Looks Like Crap…

It never ceases to amaze me what a difference “presentation” makes.

Pizza Hut is airing a commercial around here about their “Tuscani” menu. In the commercial, they show people doing the old “Surprise! Your coffee is Folgers Crystals!” trick in a fancy restaurant, except they’re serving Pizza Hut food in an “Olive Garden”-style venue.

It clearly shows my point, and that the point applies to anything… books, food, appliances, vehicles, and software, just to name the first few things that pop to mind. You can have the greatest product in the world… it exceeds expectations in every functional way… but any adjective that is instantly applied to the visual presentation (including the environment it’s presented in) will be applied to the content.

If it looks like crap, that’s what people will think of it.

(Of course, there are two sides to the coin… What really kills me are the times when a really polished application really IS crap… it’s UI is very appealing, but not thought out. It crashes at every click. But it looks BEAUTIFUL. And so people love it, at least enough to be sucked into buying it.)

Good engineers don’t go for the adage “It’s better to look good than to be good.” We know far better than that. You can’t judge the power of a car by its steering wheel. Granite countertops look great, but they’re typically hard to keep sanitary.

When it comes to application user interfaces, engineers tend to make it function great… it gives you the ability to control every nuance of the solution without allowing invalid input… but if it looks kludgy, cheap, complex, or gives hard-to-resolve error messages, you get those adjectives applied to the whole system.

So what I’m talking about, really, is a risk… and it’s a significant risk to any project. For that reason, appearance litterally becomes a business risk.

For any non-trivial application, a significant risk is end-user rejection. The application can do exactly what it’s designed to do, but if it is not presented well in the UI, the user will typically tend to reject the application sumarily.

That’s one thing that I was always happy about with the ISIS project. (I’ve blogged about our use of XAML and WPF tools in it, before.) The project was solid, AND it presented well. Part of it was that the users loved the interface. Using Windows Presentation Foundation, it was easy to add just enough chrome to impress the customers without adding undo complexity.