Wednesday, December 9, 2009

EntitySet Confusion

Okay, from the outset I have been keen on using the LINQ to SQL technology and in my enthusiasm I pressed forward and created LINQ to SQL classes from my SQL database using the handy little designer in Visual Studio.

I mucked around enough to fiqure out what it was doing and use these classes in a form, except one concept has proven a little frustrating: HOW TO USE THE DARNED ENTITYSET COLLECTIONS!  It's not that I couldn't use them, it's just that I didn't find them very useful.  Why?  Because they did not follow the rules of the other collections and I have found it extremely difficult to extract any information from Google on how to deal with them.  Today I made a few discoveries and thought I would post them so you could benefit, if only from a good laugh at my flailing around.

The Problem

When I first attempted to use these EntitySet collections I tried to follow the paradigm for sorting that works for List collections.  That is, in my XAML file:

<Grid>
  <Grid.Resources>
    <CollectionViewSource x:Key="SortedBios" Source="{Binding SelectedItem.CGBiographies, ElementName=cbxManagers, Mode=OneWay}">
      <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Name"/>
      </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
  </Grid.Resources>
  <ListBox Name="lbxBios" DisplayMemberPath="Name" ItemsSource="{Binding Source={StaticResource SortedBios}}"/>
</Grid>

The ListBox populated, but was not sorted.   After searching on the web I found some who suggested to use the EntitSet.ToList() function to return a List object.  So I added a property to my CGManager object:

  public partial class CGManager: InvestBase
  {
    public List BiographyList
    {
      get { return _CGBiographies.ToList(); }
    }
    ...

Then I changed the XAML so that the binding expression in the CollectionViewSource element referenced this property instead of the CGBiographies EntitySet and suddenly my sorting worked!  Only problem is that the List collection does not provide change notification so the ListBox will not automatically update when items are added/removed from the EntitySet.  Defeat was snatched from the jaws of victory. This is a major problem and one that needed to be solved.  Was there a way to sort these frustrating EntitSets?  

The Answer: No.

Okay, "no" for the EntitySet, but that is fortunately not the end of the story.  The EntitySet has a method GetNewBindingList() that returns an IBindingList collection.  As it turns out, this interface provides you with everything you need to not only sort, but to notify your UIElements of changes to the underlying collection.  Here is my new BiographyList property:

  public partial class CGManager: InvestBase
  {
    private BindingList<CGBiography> _BiographyList;
    public BindingList<CGBiography> BiographyList
    {
      get {
        if (_BiographyList == null)
        {
          PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(new CGBiography());
          PropertyDescriptor myProp = properties.Find("Name", true);
          IBindingList bl = (IBindingList)_CGBiographies.GetNewBindingList();
          bl.ApplySort(myProp, ListSortDirection.Ascending);
          _BiographyList = (BindingList<CGBiography>)bl;
        }
        return _BiographyList; }
    }
    ...
After adding this I completely removed the CollectionViewSource element from my XAML and bound the ListBox.ItemSource property directly to the BiographyList property.  Now the sorting happens and if you remove an item from the BiographyList, the ListBox is updated automatically.  This may have some other bumps that I haven't discovered yet, but I have confirmed that the underlying EntitySet is indeed updated through the BindingList.  I haven't spent any time trying to streamline the whole PropertyDescriptor thing, so there is probably a way to get that in a more direct manner, but I'll save that joy for another day.

I have to say, this seems like a lot of code for what should have been a much simpler task, and I am still looking for a better way to do this.  If you have one, please let me know!

PS: ObservableCollection

How about ObservableCollections?  You can create one from an EntitySet using a statement like:

_BiographyList = new ObservableCollection<CGBiography>(CGBiographies);

This results in a collection that can not only be sorted using the above XAML, but will also notify the ListBox of additions and deletions.  Unfortunately, the link between it and the EntitySet is non-existant and so additions and deletions will not be reflected in the EntitySet as they are when using the BindingList.

Friday, December 4, 2009

WPF Book Update and Icons

I'm almost half-way throught the Pro WPF in C# 2008 and I must say that it is well worth every penny.  WPF is not just some add-on to .NET, it is a major organ and this book gives you great insight into its workings.  I especially like the authors frequent use of the, "...you could do it this way, but here's another way and why it's better..."  So much better than just showing you one way to do everything since it gives you a much better picture of the why's and the wherefore's.

First Impressions

In order to cut the boredom while I slog through the reading, I've been playing around with icons.  Now you've probably stumbled across the limited icon editor in Visual Studio and I played around with it a while, but let me just recommend that you don't waste your time with it.  After searching around on the web, I zeroed in on Axialis IconWorkshop.  Yes, it sounds like an erectile dysfunction medication, but this application is just what the doctor ordered for creating and editing your icons.  It even comes with a plug-in for Visual Studio 2008.  There is a 30-day free trial, so you can try before you buy. I've just scratched the surface, but it appears to be top-drawer in most every respect.  First impressions are ever so important, and when it comes to applications your first impression will be the icon.

P.S: Don't try to put a 256x256 size icon in your *.ico file as this seems to make Visual Studio choke...

Tuesday, November 24, 2009

Pro WPF in C# 2008 - PopUps

After way to much WPF experimentation and searching the web for answers, I finally broke down and bought the book Pro WPF in C# 2008 and I have to say it was worth every penny.  I'm only 200 pages in and it has already clarified and crystallized a great deal that was tremendously fuzzy from the rudimentary coverage in Pro C# 2008 and the .NET Platform (okay, the author did encourage me to get the book). Let me just use this space to add some things I have noticed in my reading.  Here is the first:

Disappearing PopUp

On page 201-202, the book provides a  PopUp example.  When I tried to execute this example my PopUp would initially appear and then disappear correctly (when clicking on the window), but then I couldn't get it to re-appear!  After doing some experimentation I postulated that the issue might be that the IsOpen property was still set to "true" and this was preventing a show event from firing when the IsOpen property is set again (because it is not really changing).  When I added "popLink.IsOpen=false;" on the line above "popLink.IsOpen=true;" it seemed to solve the problem.

Thursday, November 12, 2009

Adventures in Making a Custom Accordion Control

As I mentioned in my previous post, I have been trying to create an Accordion control.  The one I had grabbed off the web worked pretty well, but I couldn't resist the urge to tweak it.  After more than a day of head-scratching, googling, pondering and revelation I now have a much better handle on custom controls, and a rudimentary Accordion control to show for my efforts.  I record here for posterity the steps I took along the way.

Creating a Custom Control from Scratch

WPF has numerous ways to create a custom control.  The first one I came across was called a User Control.  This control actually has it's own XAML tag.  Sounds easy (because it is) but it comes with limitations.  To get the full access to events, custom properties, etc. I needed a Custom Control. A good short summary of the differences between User and Custom can be found here.  I also found the Custom Control "tutorial" from Christian Moser to be extremely enlightening (but more of an overview than a tutorial).

The Accordion control that I started with was initially declared with a base class of StackPanel.  This gave it the functionality it needed to stack the Expander elements. Now I wanted to add the ability for the control to dynamically re-size if/when the user re-sized the containing element.  The StackPanel doesn't really seem support this functionality so at first I thought that I would just snag a reference to the parent container in the OnInitialized event handler and add a handler delegate to its SizeChanged Event:

    protected override void OnInitialized(EventArgs e)
    {
      base.OnInitialized(e);
      _parentContainer = this.Parent as FrameworkElement;
      if (_parentContainer != null)
        _parentContainer.SizeChanged += new SizeChangedEventHandler(this.OnSizeChanged);
       ...


This worked okay, but I was having trouble getting the control to size itself correctly on the initial display.  In addition, there were parent containers that could cause potential problems and I didn't have a way to guarantee that the parent of my Accordion would behave as I expected.  What if I could place my StackPanel inside a Grid element?  How could I do this?  That is where the Generic.xaml file comes in!


Expression Blend to the Rescue

In my previous post I mentioned the ability of Microsoft's Expression Blend to dump out the Style Template of a control so you could examine/change it.  This proved extremely useful in this case because I didn't know anything about ControlTemplates and dumping a few of these out and reading through them was a great help to me in getting a handle on them.  As a starter for my control's template I dumped out the template for the GroupBox control (I tried to do the StackPanel and the Grid, but apparently they don't have Templates since they are only containers and have no visual elements of their own(?)).  This was very instructive and also gave me some better ideas about XAML layout (REVELATION: I had no idea you could set Width/Height to "*" for "fill remaining" or ".3*" for "30% of remaining").

Anyway I copied this GroupBox style XAML over to my Generic.xaml and changed it accordingly.  I put a Grid element around a StackPanel around the ContentPresenter tag since I was pretty sure that the ContentPresenter was supposed to hold my Content (duh!).  When I tried to build, I got several errors about my setter trying to set non-existent dependency properties in my Accordion (like BorderBrush and BorderThickness). Darn.  I went about several rounds of adding and deleting dependency properties from my Accordion class before I realized that what I really needed to do was reconsider the base class I was using (it was still set to StackPanel).  This would have been a good time for me to re-read Mr. Moser's overview (especially section 3), but why read when you can beat your head against the wall? Eventually I settled on ContentControl which had every property my ControlTemplate needed right out of the box.  Oops, now it complained about trying to add multiple items to the ContentPresenter.  What?

ContentPresenter vs. ItemsPresenter

Okay, so in Blend I had grabbed the GroupBox template which inherits from the HeaderedContentControl which is based on the ContentControl.  ContentControl is designed to have a single (one, uno, singular) piece of content, not multiple pieces like I wanted in my Accordion.  Turns out that what I needed was a ItemsControl!  The ItemsControl works with the XAML ItemsPresenter tag.  I changed my Accordion's base class to ItemsControl and replaced the ContentPresenter tag with ItemsPresenter (which apparently doesn't need a binding statement like ContentPresenter does).  I also had to change references to the StackPanel's Children collection to the ItemsControl's Items collection.  Now I was in business, right?

Accessing the Template's Elements

I had given my Grid element in my ControlTemplate the Name of  "Container" and now all I had to do was use the following code to grab a reference to it:

_containerGrid = Template.FindName("Container", this) as Grid

At first I put this statement in the OnInitialize event handler.  It returned null.  Breaking the code there appeared to be no Template at all!  I went in to Generic.xaml and tweaked some stuff and my changes were reflected in the resulting control, so I knew that it was getting set eventually but where could I grab it?  The answer was the OnApplyTemplate event handler (sure, it sounds easy now).  This gave me a reference to the containing Grid, but unfortunately it was not laid out yet as it returned and ActualHeight property equal to 0.  That was no good.  The solution (for me) was to use the Grid's Loaded event to set the initial height of my control:

    public override void  OnApplyTemplate()
    {
      base.OnApplyTemplate();
      _containerGrid = Template.FindName("Container", this) as Grid;
      if (_containerGrid != null)
      {
        _containerGrid.SizeChanged += new SizeChangedEventHandler(this.OnSizeChanged);
        _containerGrid.Loaded += new RoutedEventHandler(this.SetInitialHeights);
      }
    }

That did it! Now my control was sizing and re-sizing appropriately.

Template.FindName Gotcha

One other thing I discovered in doing my control was that the Template.FindName() is specific to the Template.  Sure that makes sense, but I discovered that some ControlTemplates contain other Templates.  What this means is that if your Template contains a named item that also contains a Template with a named item you will have to call FindName() twice.  I discovered this when trying to get a reference to the Path named "arrow" in  the Expander's ControlTemplate.  Check out this excerpt from the Expander's ControlTemplate (extracted using Expression Blend).  I have highlighted the ControlTemplate and Named elements:

  <ControlTemplate TargetType="{x:Type Expander}">
    <Border ... >
      <DockPanel>
        <ToggleButton x:Name="HeaderSite" ... >
          <ToggleButton.Style>
            <Style TargetType="{x:Type ToggleButton}">
                <Setter Property="Template">
                <Setter.Value>
                  <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                      <Grid SnapsToDevicePixels="False" Background="Transparent">
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="19"/>
                          <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Bd" ... >
                          <Microsoft_Windows_Themes:ClassicBorderDecorator.BorderBrush>
                            <SolidColorBrush/>
                          </Microsoft_Windows_Themes:ClassicBorderDecorator.BorderBrush>
                          <Path x:Name="arrow" ... Data="M1,1.5L4.5,5 8,1.5"/>

In order to get at the "arrow" Path object you will need to first FindName() the "HeaderSite" ToggleButton and then call FindName() again on the ToggleButton's Template.  The following C# code show how I did it:

      Path arrow;
      ToggleButton toggle = expander.Template.FindName("HeaderSite", expander) as ToggleButton;
      if(toggle != null)
        arrow = toggle.Template.FindName("arrow", toggle) as Path;

Thus I obtained access to the Path for the arrows so I could make sure they were pointing appropriately. If anyone has any better more efficient ways to do any of this, I welcome your advice/wisdom!

Wednesday, November 11, 2009

The .NET Black Box

So one of my first projects has been to create an Accordion control, which is apparently missing from the .NET control library.  I found a bare bones one on the web that uses the expander and I have been playing around with it to get it to behave the way I want.  The basic XAML is below:


<custom:Accordion Height="Auto">
   <Expander Header="First" IsExpanded="True">
     <DockPanel LastChildFill="True">
       <Label Content="Big Text Box" DockPanel.Dock="Top"/>
       <TextBox/>
     </DockPanel>
   </Expander>
   <Expander Header="Second"/>
   <Expander Header="Third"/>
</custom:Accordion>


One of the behaviors that I wanted was that the only way to close the open Expander would be to select a different one.  Thus at least one Expander would always be open.  Sounds easy enough. The problem comes with the fact that Expander control only exposes two events: OnCollapsed and OneExpanded.  Clearly, these events fire AFTER their related dirty work has been accomplished so the only solution to prevent the user from collapsing the currently selected Expander was to set the IsExpanded property back to TRUE.  This does indeed prevent the Expander from collapsing (from the user's perspective), except that stupid little arrow "button" doesn't reset to the "expanded" position.  So you have an Expander that is expanded but whose little arrow indicates that it isn't.

Now the trick becomes how to access the arrow do-hicky and fix it.  But where is it?  What is it's name?  Maybe it isn't named at all?  Is it an Adorner or just a Path?  After stumbling around in Debug mode I finally decided to do some Googling.  Two things that I stumbled on that I want to share:  1) Microsoft Expression Blend 3 Template tool, and 2) Mole.  Both of these tools are a spelunker's dream come true!

Microsoft Expression Blend 3 Templates

In Blend, right click on any control and from the context menu select the "Edit Template" sub-menu and "Edit a copy...".



This handy little command will spill the controls guts to your XAML in the form of a Style tag!  Now the Expander is not a very complicated control, but the resulting XAML contains no less than 215 lines of XAML code (which I won't repeat here).  Now I have two options, I can change the template to my liking, or I can hunt down that silly little arrow and write some code to point it in the right direction.  Cool!  If you don't have Blend, you can download a 60 day trial at Microsoft Expression Blend 3.

Mole

Mole is even more exciting.  Mole was written to plug into Visual Studio and allow programmers to "visualize" the object model.  You can find the latest version of Mole here.  Holey moley!

I hope you find these two tools useful as you explore the .NET universe.  I'd write more, but I have an arrow thingy to fix.

Monday, November 9, 2009

Sizing Up WPF Container Tags and Other XAML Tips

One of the more irritating things so far in learning XAML has been the confusing array of control container tags.  These tags are meant to help your controls arrange themselves on the form and respond appropriately to changes in style or window size.  Of course you could just use the <Canvas> tag to lay out your controls the old fashioned way (specifying x and y coordinates), but why not let WPF do the layout for you?

When I started creating forms in XAML, I was trying to use as few container tags as possible (why be wasteful?).  If this is your mindset, let me just encourage you to get over it.  The container tags are your friends and to get them to work well, you need to get used to the idea of sprinkling them liberally throughout your forms.  Here are the container tags that I am aware of so far and some of the comments that I have on each.

<Grid>: Your New Best Friend
I wasn't really sure what to use this tag for in the beginning.  Probably because in Adobe Flex (which I am more familiar with) you can live a productive life without its counterpart (mostly due to the fact that in Flex, height and width can be specified in percentages of available space!).  I kept trying to get my controls to layout appropriately by just using a combination of <StackPanel> and <DockPanel> tags.  This was working fine, until I tried to re-size my window container.  That's when I went back and re-examined the <Grid> tag.Just for review, here is a bare bones <Grid> tag:

   <Grid>
     <Grid.RowDefinitions>
       <RowDefinition/>
       <RowDefinition/>
     </Grid.RowDefinitions>
     ...
   </Grid>


Now, the <Grid> tag will automatically size its rows (and columns) evenly, thus if the Grid is 200 pixels tall and you have two rows, each row will be 100 pixels tall.  Grids will then re-size accordingly when the Window container is re-sized (unless you specify a fixed Height/Width for the Grid itself).  If you want the row (or column) to match the size of the elements it contains the set Height="Auto".  This will force the specific row/column to adopt the minimum size necessary to display it contained controls.  The remaining rows/columns will split up the remaining space.  For example, I had a column of form controls in a form with a large, scrollable text box in the middle that I wanted to expand if the user stretched window vertically.  I accomplished this as follows:


  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0">
     ... SOME FIXED HEIGHT CONTROLS ...
    </StackPanel>
    <DockPanel Grid.Row="1" LastChildFill="True">
      <Label DockPanel.Dock="Top" Content="Stretchable:" Width="Auto" HorizontalAlignment="left"/>
      <TextBox/>
    </DockPanel>
    <GroupBox Grid.Row="2" Header="Contact">
     ... SOME FIXED HEIGHT CONTROLS ...
    </GroupBox>
  </Grid>

Bingo! Note that DockPanel has LastChildFill="True".  This forces the TextBox to fill the width of the container (see the next section). The middle Grid row re-sizes automatically to fit the remaining space and the top and bottom rows size themselves (due to the Height="Auto" attribute) to fit their content.  Now that I had figured this out I started using <Grid> all over the place.  Even nesting <Grid> tags inside of <Grid> tags. 


<DockPanel>: Two's Company
The main use that I have found for the <DockPanel> is a Label-Control combination.  Because this container has the "LastChildFill" attribute, you can pair a fixed width <Label> with another control (such as a <TextBox>) and the second control will expand to fill the available space.  The <DockPanel> default stacking behavior is horizontal, meaning that multiple controls line up from left to right like text.  If you want the <Label> to sit above your control (like the stretching <TextBox> in the <Grid> example above) then set the <Label> tag's DockPanel.Dock="Top" attribute.  Because I most often use the <DockPanel> tag in this manner, I usually set default styles for it and the <label> tag:
  <Style TargetType="{x:Type DockPanel}">
    <Setter Property="LastChildFill" Value="True"/>
  </Style>
  <Style TargetType="{x:Type Label}">
    <Setter Property="Width" Value="60"/>
    <Setter Property="FontWeight" Value="Bold"/>
  </Style>

Incidentally, the LastChildFill property refers to the last XAML child not it's visual position in the DockPanel.  For example, if you want a expanding TextBox above a row of buttons, then place the buttons in a StackPanel (Orientation="Horizontal") with DockPanel.Dock="Bottom" and as the last XAML element in the DockPanel place your TextBox. Since I'm on the topic, order is extremely important in the DockPanel layout.  Try re-ordering controls inside a DockPanel tag while keeping their Dock attribute fixed (i.e., Top, Bottom, Left or Right) and notice how the layouts differ.

<StackPanel>: No Surprises Here
I generally use <StackPanel> as a container for other containers.  Usually the child container of choice is a <DockPanel> which is used as a Label-Control pair as described above. 


<GroupBox>: Bold That Header, Darn It!
Call me crazy, but I prefer all my control labels to be bold.  The <GroupBox> control gave me a little trouble at first because I couldn't figure out how to set a style for this.  If you just try to set the "FontWeight" attribute then ALL of the text inside your <GroupBox> will be bold in addition to the header.  Fortunately, I was able to stumble onto the following code on the web posted by some generous and like-minded soul whose name escapes me.

  <Style TargetType="{x:Type GroupBox}">
    <Setter Property="HeaderTemplate">
      <Setter.Value>
        <DataTemplate>
          <TextBlock Text="{Binding}" FontWeight="Bold" HorizontalAlignment="Stretch"/>
        </DataTemplate>
      </Setter.Value>
    </Setter>
  </Style>

Binding Made Easy(er)
You may have discovered that Data Binding statements can be a little confusing and tricky.  This is mostly due to the bare bones intellisense that VS2008 offers for them.  In this regard I have found Microsoft Expression Blend 3 to be invaluable. Data Binding is accomplished through a slick user interface that writes the binding statement for you.  Nice. It's pretty spendy, but it does have a 60-day full featured trial that will allow you to get a good idea of what it can do as well as get a good handle on Data Binding expressions.

Using a Base Class with LINQ Generated Classes

I am using a custom TreeView control in a form that utilizes the generic syntax to provide greater type-safety and increased functionality .  This control utilizes an abstract class of TreeViewBase.  In order to use the control you must declare you TreeView class like so:

  //a tree control that handles InvestBase objects
  public class ProductTree : TreeViewBase<InvestBase>
  {
    //the sample uses the category's name as the identifier
    public override string GetItemKey(InvestBase item)
    {
      return item.ItemKey;
    }

    //returns subcategories that should be available 
    //through the tree
    public override ICollection<InvestBase>   
    GetChildItems(InvestBase parent)
    {
      return parent.Children;
    }

    //get the parent category, or null if it's a root category
    public override InvestBase GetParentItem(InvestBase item)
    {
      return item.Parent;
    }

    public TreeViewItem SelectedNode
    {
      get { return this.TryFindNode(this.SelectedItem); }
    }
  }

I did this in my MainWindow.xaml.cs file.  Notice the InvestBase class that I have used for the generic .  The next step was to declare the base class.  Below is the declaration of the InvestBase base class.  Notice that I wanted to expose several of the LINQ defined properties and even an EntitySet collection using virtual properties, as well as defining some basic functionality that could be overriden:


  public abstract class InvestBase
  {
    #region Basic Properties
    public virtual System.Guid KeyID { get; set; }
    public virtual string Name { get; set; }
    public virtual EntitySet<CGChart> CGCharts { get; set;}
    public virtual string Notes { get; set; }
    public virtual string Description { get; set; }
    public virtual bool Active { get; set; }
    public virtual string ObjectType
    {
      get { return this.GetType().ToString(); }
    }
    #endregion

    #region Charting
    /// List the available Charts and keep track of the 
    /// last one selected;
    protected CGChart _SelectedChart;

    public virtual List<CGChart> ChartList
    {
      get { return CGCharts.ToList();}
    }

    public virtual CGChart SelectedChart
    {
      get 
      {
        if(_SelectedChart==null && CGCharts.Count>0)
          _SelectedChart = CGCharts[0];
        return _SelectedChart;
      }
      set { _SelectedChart = value;}
    }
    #endregion

    #region TreeViewBase Members
    public virtual IEnumerable<InvestBase> TreeRoot
    {
      get
      {
        List<InvestBase> treeList = new List<InvestBase>();
        treeList.Add(this);
        return treeList;
      }
    }

    public virtual string ItemKey
    {
      get { return KeyID.ToString(); }
    }

    public virtual string NodeLabel
    {
      get { return Name; }
    }

    public abstract string ImagePath {get;}
    public abstract ICollection<InvestBase> Children { get; }
    public virtual InvestBase Parent { get; set; }
    #endregion
  }

Next I placed this base class in a partial class declaration for the three classes that would be in my tree control.  Below I show CGManager and just the header for the CGProduct and CGStrategy classes because these are similar:

  public partial class CGManager: InvestBase
  {
    ...

    #region TreeViewBase Members
    public override string ImagePath
    {
      get { return "/Images/manager.png"; }
    }

    public override ICollection<InvestBase> Children
    {
      get
      {
        List<InvestBase> strats = new List<InvestBase>();
        foreach (var s in _CGStrategies)
        {
          strats.Add(s);
        }
        List<InvestBase> prods = new List<InvestBase>();
        foreach (var p in CGProducts)
        {
          if (p.CGStrategy == null) prods.Add(p);
        }
        strats.AddRange(prods);
        return strats;
      }
    }

    #endregion
  }

  public partial class CGStrategy : InvestBase
  {
    ...
  }
 
  public partial class CGProduct : InvestBase
  {
    ...
  }

This all compiles just fine since the automatically generated LINQ classes (CGManager, CGStrategy and CGProduct) are also generated as partial class definitions.  The problems start with my virtual properties since C# does not associate these with the base class’ default functionality. For example, the ItemKey virtual method tries to pass back the KeyID property, but since the “override” keyword is never found in the LINQ KeyID property, the compiler assumes we want the InvestBase.KeyID which is null!  


Now you can’t add or change any of the code in the designer generated file where the LINQ classes are declared.  If you try, it will just get over-written.  What I found is that you can set an “Inheritance Modifier” in the *.dbml file for properties and even for associations.  For properties:




And for associations:



NOTE: Make sure to “Clean” your project before you re-build it.  Sometimes this may cause the *.designer.cs file to completely disappear from your project!  Don’t panic.  Just rename the associated *.dbml file to something else (I just tack a “_OLD” onto the end) and the designer file will magically re-appear.  Rename the stupid *.dmbl file back and all will be right with the world and you should be able to build your project.


Once you set the “override” inheritance modifiers on all your virtual properties, the compiler will now find the LINQ property instead of the base class’ one.