Taming the WPF Expander Control



How to Enable Using the Binding Builder in WPF and Silverlight Applications


When the Data Sources Window is used to generate the UI, the generated XAML injects design-time information so that the Binding Builder can be used to create bindings for the UI controls.

What if your application was written in Visual Studio 2005 or 2008; or you used the XAML Editor, the Designer or Expression Blend without the Data Sources Window and you now want to take advantage of the new Binding Builder?

What if your coding style is to assign the DataContext for your forms in code and not data bind to CollectionViewSources in your XAML?

This very short walk-though will demonstrate the simple requirements to enable you to use the new Binding Builder in a variety of scenarios like the ones mentioned above.

Requirements

This walk-through assumes you have the opened the attached solution. The attached zip file contains both a VB.NET and C# version of the solution.

Table of Contents

  1. Why use the Binding Builder?
  2. What is the Problem we Trying to Solve?
  3. Design-Time Properties
  4. Let's Implement the Solution
  5. Binding Builder in XAML View
  6. Links
  7. Comments

Why use the Binding Builder? 

The Binding Builder makes it easier to set up bindings and more importantly makes it easier to create accurate bindings so that you don't need to debug so often. This alone will save you time, limit frustration and increase your productivity.

If you add to this all the other improvements in the WPF and Silverlight Designer like the image picker, the resource picker, the brush editor, etc. I believe that we have a much-improved experience for WPF and Silverlight developers in Visual Studio 2010.

What is the Problem we Trying to Solve? 

Let's first run the application to get a feel for how it works at run-time. After starting the application change the selected Customer using the ComboBox at the top. Resize the application; notice how the DataGrid allows data editing.

This application was hand coded using the XAML Editor and the DataContext is set in the Loaded event of the Window. As a result, the tooling has no way to determine the DataContext at design-time; additionally, the Binding Builder will have no way to list properties in its Path section.

A picture is worth a thousand words so…

  • Open MainWindow.xaml in the Designer

  • Select the ComboBox to the right of the Select Customer TextBlock

  • Using the Properties Window:

    • Click on the ItemsSource property Property Marker pointed to by the red arrow
    • Select Apply Data Binding… from the Context Menu
    • Optionally, you can also click the gray text to the right of the Property Marker to open the Binding Builder

  • In the below image we have two problem indicators

    • First, the DataContext is null. This is indicated by the text pointed to by the top red arrow; it does not display class type name that is assigned to the DataContext or what class type name the DataContext is inheriting from.
    • Second, since the DataContext is null, the Path Customers pointed to by the bottom red arrow; cannot be resolved by the Binding Builder which is indicated by the dash line under the Path property name.

Let's look at one more example.

  • Select the TextBox to the right of the Email Label
  • Using the Properties Window open the Binding Builder for the Text property
  • First, the DataContext is bound to Object. Object does not have properties we can use to set the binding paths.
    • In this case, the TextBox is inheriting DataContext from the parent Grid control
    • The parent Grid control has its DataContent bound to the SelectedItem of the ComboBox, which is why the Email TextBox has its DataContext set to Object.
  • Second, the Email TextBox Text property path is set to Email but like the previous example, it has a dashed underline indicating the Binding Builder was unable to resolve the Email property path.

Design-Time Properties 

The problem we need to solve is how to provide "a shape" to the Binding Builder at design-time. When I say "shape" I mean an instantiated Type that the Building Builder can reflect over and then list those properties in the Path selection tab to establish the binding.

In this walk-through we will use the d:DataContext property and d:DesignInstance MarkupExtension.

The "d:" in above property and Markup Extension is the alias to the design namespace where the all the design properties are members of. Here are links to MSDN topics that cover all the "d:" properties and Markup Extensions.

The "d:" properties and Markup Extensions cannot be created in user code or extended in user code; they can only be used in XAML.

The "d:" properties and Markup Extensions are not compiled into your application; they are only used by the Visual Studio WPF and Silverlight Designer and Expression Blend tooling.

d:DataContext Property

d:DataContext, specifies a design-time data context for a control and its children. When specifying d:DataContext, you should always provide the same "shape" to the design-time DataContext as the run-time DataContext.

If both a DataContext and d:DataContext are specified for a control, the tooling will use the d:DataContext.

d:DesignInstance Markup Extension

If MarkupExtensions are new to you, please read this MSDN topic Markup Extensions and WPF XAML.

d:DesignInstance, returns the an instantiated Type ("shape") that you want to assign as the data source for binding to controls in the designer. The type does not need to be creatable to be used for establishing "shape."

d:DesignInstance MarkupExtension Properties

Type

Name of the Type that will be created. Type is the default parameter in the constructor.

IsDesignTimeCreatable

Defaults to False. Is the specified type creatable? When false, a faux type will be created instead of the "real" type.

CreateList

Defaults to False. When true, will return generic list of the specified type.

Visual Studio Markup Extension IntelliSense

The XAML Editor in Visual Studio 2010 provides IntelliSense when editing Markup Extensions, making the entry of design-time properties and Markup Extensions easy.

Let's Implement the Solution 

In this application's Loaded event, I assign the Data class to the Window's DataContext property. To follow this same pattern, we need to assign the Data class to a design-time DataContext or d:DataContext to either the Window or top level Grid control in the XAML file. By doing this, we are allowing the d:DataContext to be inherited down the tree of elements, just like it does when the application is at run-time.

The below red arrow indicates DataContext inheritance for the Grid control's child controls. Notice how the ComboBox ItemsSource property is bound to the Customers property on the inherited DataContext, which is the Data class.

Top ComboBox

  • Change MainWindow.xaml into XAML View
  • Locate the root Grid named "layoutRoot" add the following XAML as pictured below:
 d:DataContext="{d:DesignInstance local:Data}"  

  • Change MainWindow.xaml back to Design View

  • Select the ComboBox

  • Using the Properties Window, open the Binding Builder for the ItemsSource property:

    • First, the DataContext now has a "shape," the Data class
    • Second, the Customers Path property name is no longer has a dashed underline because, the Building Builder can resolve the property name on the DataContext
    • Third, since Data.Customers is a collection, the individual properties of the Customer class are now listed in the Path section as part of the Current Item. These properties would be used if we were editing a DataTemplate for the ComboBox.

Middle Data Form

The below red arrow indicates d:DataContext inheritance for the child controls of the Grid; this enables property resolution for the Binding Builder tool.

  • Change MainWindow.xaml into XAML View
  • Locate the middle Grid that has its DataContext bound as pictured below and then add the following XAML as pictured below:
 d:DataContext="{d:DesignInstance local:Customer}"  

  • Change MainWindow.xaml back to Design View

  • Select the Email TextBox

  • Using the Properties Window, open the Binding Builder for the Text property:

    • First, the Customer ID TextBlock now displays a 0. This is because the design-time DataContext is now a real instance of the Customer class. The CustomerID property is an Int32 that has a value of 0
    • Secord, the DataContext now has a "shape," the Customer class
    • Third, the Email Path property name is no longer has a dashed underline because, the Building Builder can resolve the property name on the DataContext
    • Fourth, all of the properties exposed by Customer type are available for selection in the Path section of the Binding Builder

DataGrid

At run-time, the Grid's DataContext is a collection of Addresses that comes from the Addresses collection property on the selected Customer class.

Now we need to provide the same "shape" to the design-time DataContext of the Grid.

The below top red arrow indicates d:DataContext inheritance for the child controls of the Grid; the ItemsSource for the DataGrid is a collection of Addresses at both design-time and run-time.

The individual rows in the DataGrid will each be bound to an instance of the Customer class. The bottom red arrow indicates the relationship between the ItemsSource property and the individual properties that are bound to each DataGridRow.

  • Change MainWindow.xaml into XAML View
  • In the next step, we will use the d:DesignInstance Markup Extension to create a list of Address instances for the design-time DataContext
  • Locate the Grid control at the bottom of the file. Add the following XAML as pictured below:
 d:DataContext="{d:DesignInstance local:Address, CreateList=True}"   

  • Change MainWindow.xaml back to Design View
  • Select the DataGrid by clicking it like the below image on the left
  • Using the Properties Window, open the Columns property Collection Editor by clicking the ellipsis button as in the below image

  • First, select the first DataGridTextColumn

  • Second, click the Binding property Property Marker, select Apply Data Binding… from the Context Menu:

    • Third, the DataContext "shape" is the Address class
    • Fourth, Street is not underlined with dashes
    • Fifth, all of the properties exposed by Address type are available for selection in the Path section of the Binding Builder

Binding Builder in XAML View 

Developers working in the XAML Editor will be surprised to know that the Properties Window and its features like selection sync with the XAML Editor, Binding Builder, Resource Picker and Image Picker continue to work even if the Designer is not visible.

In order to utilize the Properties Window in the XAML Editor, the Designer must load, not necessarily be visible.

If you open a XAML View and the Properties Window does not load, momentarily switch to Design View then back to XAML View by clicking these two tabs pictured below.

Notice the Grid is selected in XAML View and is displayed in the Tag Navigator.

Links 

MSDN topic Data Binding Overview (must read for all WPF and Silverlight developers)

MSDN topic Walkthrough: Using a DesignInstance to Bind to Data in the WPF Designer

MSDN topic Design-Time Attributes in the WPF Designer

MSDN topic Design-Time Attributes in the Silverlight Designer

MSDN topic Walkthrough: Using a DesignInstance to Bind to Data in the Silverlight Designer

MSDN topic Markup Extensions and WPF XAML

Comments 

Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above features enable your workflow
  • What is missing from the above features that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett

Expression Team

EnablingTheBindingBuilder.zip


How to Insert a Row in a Data Entry Form


This article has a corresponding video that can be viewed here.

A common task after a form is developed is inserting a new row in the form. This short walk-through will show you how to insert a new row in an existing data entry form.

For this exercise our requirement is to insert a Label and TextBox for the middle initial. This row needs to be inserted between the first and last name rows.

Inserting a row is easy. Remember that when you create a row using the Grid designer, you are in effect splitting a row.

Table of Contents

  1. Steps
  2. Step One – Verify the Grid Can Grow
  3. Step Two – Set Target Row to be Split to Fixed Size
  4. Step Three – Increase Target Row Size
  5. Step Four - Add New Row by Splitting the Target Row
  6. Step Five – Set Split Row Sizes
  7. Step Six – Add New Controls, Set Control Sizing, Auto Size Row
  8. Comments
  9. Video

Steps

  • Verify the grid can grow, if not provide additional space for the new row
  • Set the target row to be split to Fixed sizing
  • Increase target row size
  • Add new row by splitting the target row
  • Set split row sizing
  • Add new controls, set control sizing, set row sizing

Before and After Inserting a New Row

BeforeandAfter

Figure 1 Before and After 

Step One – Verify the Grid Can Grow

  1. Check to see if the Grid can grow.
    1. If the Grid has a Star size row this takes care of this requirement.
    2. If not resize the container that the Grid is a child of to allow the Grid to grow in height.

Step Two – Set Target Row to be Split to Fixed Size

SettingRowToFixedSize

Figure 2 Setting Target Row to Fixed Size

  1. Using the Grid row size selector, set the row you need to split to Fixed size.

Step Three – Increase Target Row Size

InsertRowOne

Figure 3 Increase Target Row Size

  1. In the XAML editor or Properties Window, set the row height you are splitting to a higher value. For this example the row was resized to 60.

Step Four - Add New Row by Splitting the Target Row

InsertRowTwo

Figure 4 Add New Row by Splitting the Target Row

  1. Click on the Grid rail to add a new row.
    1. If you click above or below the existing controls you won't cause those controls to span across two rows.
    2. If you add the row and the Grid line is touching the existing controls, those controls will be spanned across two rows. In this case after you have inserted the new row, you'll need to also remove the Grid.RowSpan attached property from those controls.
  2. In Figure 4 above the new row was added above the existing controls in the row.
  3. When the new row is inserted, controls in higher numbered rows have their Grid.Row attached property automatically incremented.

Step Five – Set Split Row Sizes

InsertRowThree

Figure 5 Inserting Row Step Three

  1. Use the Grid row size selector and set the last name row to Auto size.
  2. Use the XAML editor or Properties Window and set the new row's Fixed size to 35.

Step Six – Add New Controls, Set Control Sizing, Auto Size Row

InsertRowFour

Figure 6 Add New Controls, Set Control Sizing, Auto Size Row

  1. Drag a Label to the first column, second row.
    1. Using the designer, resize the Label so that it fits in the first column.
  2. Using the Properties Window set the following properties on the new Label:
    1. Height to Auto
    2. Width to Auto
    3. VerticalAlignment to Center
    4. HorizontalAlignment to Stretch
    5. Margin to 3.5
    6. Content to Middle Initial
  3. Drag a TextBox to the second column, second row.
  4. Using the Properties Window set the following properties on the new TextBox:
    1. Height to Auto
    2. Width to 25
    3. VerticalAlignment to Center
    4. HorizontalAlignment to Left or Stretch. If using fixed width use Left or if using Auto width use Stretch.
    5. Margin to 3.5
  5. Using the Grid row size selector, set the new row to Auto size.
Note

The Margin of 3.5 conforms to the spacing requirements documented here: https://msdn.microsoft.com/en-us/library/aa511279.aspx#spacing

You have just quickly inserted a new row in your data entry form.

Comments

Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above features enable your workflow
  • What is missing from the above feature that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett
Visual Studio Cider Team


How to Layout a Data Entry Form


This article has a corresponding video that can be viewed here.

The WPF & Silverlight Designer provides the ability to quickly layout a data entry form. This walk-through will provide a workflow for laying out Labels and TextBoxes using the Grid control as the layout panel.

Table of Contents

  1. Completed Form UserControl
  2. Step One – Add Rows and Columns and Controls
  3. Step Two – Auto Size Label Controls
  4. Step Three – Auto Size TextBox Controls
  5. Step Four – Auto Size Rows
  6. Step Five – Size Columns
  7. Video
  8. Comments

Completed Form UserControl 

UserControlLayoutComplete

Figure 1 Completed Form

Step One – Add Rows and Columns and Controls 

UserControlLayoutOne

Figure 2 Data Entry Form Step One

  1. Add a new UserControl to your project.
  2. Select the root Grid by clicking inside the UserControl.
  3. Add a column by clicking on the upper Grid rail in the desired location.
  4. Add three rows by clicking on the Grid rail in the desired location.
  5. Drop the required Label controls in the first column.
  6. Drop the required TextBoxes or other controls in the second column.
Tip

Notice that the column width is 137. The default width of a Label control when added from the ToolBox is 120. Making the target column wider than the Label makes it easy to initially drop the Label control on the design surface.

The row heights are also unimportant at this stage. Creating the rows taller than the Label or TextBox control makes it easy to create the controls.

Step Two – Auto Size Label Controls 

UserControlLayoutTwo

Figure 3 Data Entry Form Step Two

  1. Multi-select the Label controls by CTRL+clicking each control on the design surface or use the Document Outline.
  2. Using the Properties Window set the following properties:
    1. Height to Auto
    2. Width to Auto
    3. VerticalAlignment to Center
    4. HorizontalAlignment to Stretch
    5. Margin to 3.5
Note

The Margin of 3.5 conforms to the spacing requirements documented here: https://msdn.microsoft.com/en-us/library/aa511279.aspx#spacing

Step Three – Auto Size TextBox Controls 

UserControlLayoutThree

Figure 4 Data Entry Form Step Three

  1. Multi-select the TextBox controls by CTRL+clicking each control or use the Document Outline.
  2. Using the Properties Window set the following properties:
    1. Height to Auto
    2. Width to desired fixed value or Auto
    3. VerticalAlignment to Center
    4. HorizontalAlignment to Left or Stretch. If using fixed width use Left or if using Auto width use Stretch.
    5. Margin to 3.5

Step Four – Auto Size Rows 

UserControlLayoutFourA

Figure 5 Resizing Grid Rows

  1. Resize the rows with Labels to Auto.
    1. Hover the mouse over the left grid rail.
    2. The Grid Row size selector will appear.
    3. Click on Auto.
    4. Repeat for each row.

UserControlLayoutFourB

Figure 6 Data Entry Form Step Four

Figure 6 above shows the form with each row with controls set to Auto size.

Step Five – Size Columns 

UserControlLayoutFive

Figure 7 Data Entry Form Step Five

  1. Assign the Content property to each Label control.
  2. Set column one of the Grid to fixed size of 100.
    1. If you need to localize your application you can leave the Label column set to Auto size. Then when the Label text grows wider when a different language is used at runtime the Label column will automatically grow in size.
    2. If space is a consideration, the TextBlock control provides text wrapping. Using the same technique also set the MaxWidth property on the column. This will ensure that the column is never wider than this value. If the TextBlock text is wider than the MaxWidth it will wrap its text. Since the rows are Auto sized, when the text wraps that row's height will be increased to accommodate the wrapped text.
  3. Set column two of the Grid to Star size.
Note

The Grid row and column size selector does not allow changing of the numeric values for Fixed or Star sizes. Instead use the Properties Window or XAML editor.

Comments 

Microsoft values you opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above features enable your workflow
  • What is missing from the above feature that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett
Visual Studio Cider Team


Known Issue: Attached Property ListBox.AlternationIndex Causes Error in Designer


Known Issue

When writing ListBoxItem triggers in a style that trigger on the ListBox.AlternationIndex attached property value, if you use the valid syntax ListBox.AlternationIndex like the first trigger below, the designer will display the following error:

Error Property 'AlternationIndex' was not found in type 'ListBox'… 

Workaround

The workaround is to use the alternate valid syntax  ItemsControl.AlternationIndex as the second trigger below does.

 <Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">   <Setter Property="Background" Value="Blue"/>   <Setter Property="Foreground" Value="White"/>   <Style.Triggers>    <!-- valid XAML but does not work in the designer and causes an error -->    <Trigger Property="ListBox.AlternationIndex" Value="1">     <Setter Property="Background" Value="CornflowerBlue"/>     <Setter Property="Foreground" Value="Black"/>    </Trigger>      <!-- valid alternate XAML that works in the designer -->    <Trigger Property="ItemsControl.AlternationIndex" Value="2">     <Setter Property="Background" Value="LightBlue"/>     <Setter Property="Foreground" Value="Navy"/>    </Trigger>   </Style.Triggers>  </Style>  

Comments

Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above features enable your workflow
  • What is missing from the above feature that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett

Visual Studio Cider Team


Known Issue: Control Design-Time Assemblies File Locking When Using WPF and Silverlight Designer


File Locking Issues when using WPF and Silverlight Designer

When creating and testing a registered assembly (e.g. an assembly registered via TCI), it is possible to run into a file locking issue that causes compilation to fail.  While there are a few different manifestations of this particular issue, the root cause is the same.  Visual Studio 2010 treats any assembly found in the GAC, Private Assemblies folder, or Registry as a framework assembly and thus locks these files.  Once these assemblies are loaded by the designer, any attempt to copy over them will fail with the following error message:

Unable to copy file "obj\Debug\<Assembly Name>" to "..\..\<Assembly Name>". The process cannot access the file '..\..\<Assembly Name>' because it is being used by another process.

It does not matter if this copy is happening as the result of a compilation; build action, or manual copy.  Once these assemblies are loaded by Visual Studio, they will be locked and attempts to overwrite these files will fail.

Recommended Rules to Avoid Locking Issue

To avoid this scenario, you should follow these rules for development and deployment testing of your registered assemblies: 

  • If at all possible, assembly deployment testing (e.g. assembly registration) should not be done on the same machine as development of the assembly.  This is the definitive way to avoid this issue.   Also, if the assembly you're building is using a public key and has already been registered on your development box, you have no choice but to follow this rule.  There is no other reliable way around this issue. Two popular examples of projects that use a public key are the WPF toolkit and the Silverlight toolkit.  If you download and install these toolkits, you will see this locking issue (regardless of what the project output path is set to) if you attempt to also build these toolkits on the same machine.
  • If, however, your assembly does not use a public key, and you must do development and deployment testing on the same box, you will need to follow these rules instead:
    • Make sure your project output does not write directly to a path which has been registered in any way.  For example, your output path should never be to any path that's registered in AssemblyFoldersEx.
    • Any Visual Studio instance which has already loaded your assembly must be closed before you can either rebuild the assembly, or copy a new version of the assembly to the registered path. For example, if you're using a different Visual Studio instance for testing, you will need to close this test instance of VS before you can rebuild or replace the assemblies that have been loaded by this instance.

Recommended Pattern for Testing Controls During Development

First, it's important to point out that TCI registration is not required to develop/test/debug design-time features.   It is recommended that you separate out the functional testing of control libraries from the testing of deployment scenarios.  One easy way to accomplish this is to create a test project directly in your working solution.  This will allow you to take full advantage of the Toolbox Auto-pop and will make it easy to create controls from the toolbox, all without the need for TCI registration.  You do need to ensure that the controls that you are building have not been placed in the GAC, Private Assemblies Folder, or in the registry (such as under the AssembyFoldersEx node). 

Please contact us if you need additional help with this issue.

WPF & Silverlight Designer Team


Known Issue: Controls and GAC, Toolbox and TCI


Introduction

The purpose of the post is to provide guidance for control authors to limit the controls added to the Toolbox and that are listed in the Choose Items Dialog.

The word "controls" in this post is defined as "any public type in a control assembly that derives from FrameworkElement or above." Both the TCI and Choose Items Dialog include all public types that derive from FrameworkElement or above.

Does This Information Apply To My Control Assemblies?

If your control assemblies are installed in the GAC and you want to limit controls visible in the Choose Items Dialog you must follow the guidance in this post.

If you use the TCI to have Visual Studio install your controls in the Toolbox and you install your control assemblies in the GAC and want to limit controls installed into the Toolbox and controls visible in the Choose Items Dialog you must follow the guidance in this post.

If you use the TCI to have Visual Studio install your controls in the Toolbox, you must have a design-time assembly to limit controls installed in the Toolbox. This applies to both WPF & Silverlight controls.

This post covers two known issues.

  • WPF only. Public types in control assemblies installed in the GAC that derive from FrameworkElement or above are now required to be decorated with the System.ComponentModel.DesignTimeVisible(false) attribute in order to keep the type from appearing in the Toolbox or the Choose Items Dialog. Not decorating the type with this attribute, could result in the type being added to the Toolbox and will result in the type being listed in the Choose Items Dialog.
  • WPF and Silverlight. Control assemblies that are installed using the TCI require a design-time assembly to limit the types added to the Toolbox and the Choose Items Dialog. Without the design-time assembly, all types deriving from FrameworkElement or above will be placed in the Toolbox and will be listed in the Choose Items Dialog.
Critical

If a control assembly is installed into the GAC and uses the TCI, you must implement both of the above steps to keep unwanted types out of the Toolbox and Choose Items.

Scenario Assemblies

The following two WPF assemblies are assumed for this post.

  • C:\Acme\Acme.Controls.dll
  • C:\Acme\Acme.Controls.Design.dll

Acme.Controls.dll

Each of the below four custom controls has a two line summary comment.  The first line of the comment describes what if any metadata is associated with the control in the design assembly.  The second line applies to the control itself.  The name of the control describes when the control will be visible.

 namespace Acme.Controls {      /// <summary>    /// This control has a design assembly ToolboxBrowsableAttribute false.    /// This attribute only gets processed when this assembly is in the GAC.    /// </summary>    [DesignTimeVisible(false)]    public class YouShouldNeverSeeMe : Control {    }      /// <summary>    /// This control has a design assembly ToolboxBrowsableAttribute true.    /// This control will be in the Toolbox and Choose Items.    /// </summary>    public class ToolboxBrowsableAttributeTrue : Control {    }      /// <summary>    /// This control has a design assembly ToolboxBrowsableAttribute false.    /// This control will not be in the Toolbox or Choose Items unless this assembly is loaded in the GAC.    /// </summary>    public class OnlyShowsInChooseItemsWhenInGAC : Control {    }      /// <summary>    /// This control does NOT have a design assembly ToolboxBrowsableAttribute.    /// WARNING: This control will always be loaded in the Toolbox and will be visible in Choose Items.    /// </summary>    public class FrameworkElementAlwaysShows : FrameworkElement {    }  }  

Acme.Controls.Design.dll

The below design assembly applies to the above control assembly.

The ToolboxBrowsableAttribute can be created two ways, both syntaxs create the required attribute:

 //This should be in AssemblyInfo.cs - declaring here to make it obvious  //This attribute is used to determine which class to load to register metadata  [assembly: ProvideMetadata(typeof(Acme.Controls.Design.RegisterMetadata))]    namespace Acme.Controls.Design {      internal class RegisterMetadata : IProvideAttributeTable {        public Microsoft.Windows.Design.Metadata.AttributeTable AttributeTable {        get {          AcmeControlsAttributeTableBuilder obj = new AcmeControlsAttributeTableBuilder();          return obj.CreateTable();        }      }    }      class AcmeControlsAttributeTableBuilder : AttributeTableBuilder {        public AcmeControlsAttributeTableBuilder() {        AddTypeAttributes(typeof(ToolboxBrowsableAttributeTrue), ToolboxBrowsableAttribute.Yes);        AddTypeAttributes(typeof(OnlyShowsInChooseItemsWhenInGAC), ToolboxBrowsableAttribute.No);        AddTypeAttributes(typeof(YouShouldNeverSeeMe), ToolboxBrowsableAttribute.No);      }            void AddTypeAttributes(Type type, params Attribute[] attribs) {        base.AddCallback(type, builder => builder.AddCustomAttributes(attribs));      }    }  }  

Scenario: TCI Toolbox Install

AssemblyFoldersEx Registry Entry

The following two registry entries will install the controls into the Toolbox under the Acme Toolbox tab.

[HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0\AssemblyFoldersEx\Acme]

@="c:\\Acme\\"

[HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0\AssemblyFoldersEx\Acme\Toolbox]

TabName="Acme"

How to Limit Types in the Toolbox and Choose Items Dialog when the Assembly is Not in the GAC

In the design assembly, add the ToolboxBrowsableAttribute.No to a public control assembly type's metadata to hide it. 

How to Limit Types in the Toolbox and Choose Items Dialog when the Assembly is in the GAC

In the design assembly, add the ToolboxBrowsableAttribute.No to a public control assembly type's metadata to hide it.

In the control assembly, decorate public types with the DesignTimeVisible(false)attribute to hide it.

Scenario: No TCI, Just Choose Items Dialog

How to Limit Types in the Toolbox and Choose Items Dialog when the Assembly is Not in the GAC

In the design assembly, add the ToolboxBrowsableAttribute.No to a public control assembly type's metadata to hide it.

How to Limit Types in the Toolbox and Choose Items Dialog when the Assembly is in the GAC

In the design assembly, add the ToolboxBrowsableAttribute.No to a public control assembly type's metadata to hide it.

In the control assembly, decorate public types with the DesignTimeVisible(false)attribute to hide it.

Comments

Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above features enable your workflow
  • What is missing from the above feature that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett

Visual Studio Cider Team


Known Issue – Controls Deriving From A Generic Base Class Must Be In Separate Assembly


There is a known issue when using the Visual Studio 2010 WPF & Silverlight Designer or XAML Editor and a control derives from a generic base class.  The control and generic base class must be located in separate assemblies, otherwise the Designer and XAML Editor will display the following error:

Error 1 The type 'local:GenericBase' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built

The listed error will not prevent you from using the Designer or building your application.  However, its a misleading error message that does not help you correct the design-time problem.

Workaround

To workaround this issue, you'll need to place the generic base class in a separate assembly from the control as pictured below.

In this example the UserControlWithGenericBase derives from GenericBase and the two types are located in separate assemblies.

solutionexplorer classdiagram

TypeArguments Property

In the above class diagram you can see that UserControlWithGenericBase derives from:

  • C#  GenericBase<String> 
  • VB – GenericBase(Of String)

Notice the third line of XAML, the x:TypeArguments property is set to sys:String.  This matches the generic type argument passed to GenericBase in the above class diagram and the UserControlWithGenericBase UserControl class declaration below.

x:TypeArguments is required when the base class is a generic type.

 <gbc:GenericBase    xmlns:sys="clr-namespace:System;assembly=mscorlib"    x:TypeArguments="sys:String"    xmlns:gbc="clr-namespace:GenericBaseClassLibrary;assembly=GenericBaseClassLibrary"    x:Class="UserControlDerivingFromGenericTypeCS.UserControlWithGenericBase"    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"     xmlns:d="https://schemas.microsoft.com/expression/blend/2008"     mc:Ignorable="d"     d:DesignHeight="300" d:DesignWidth="300">      <Grid>    </Grid>    </gbc:GenericBase>  

C# Code

 public partial class UserControlWithGenericBase : GenericBase<String> {    public UserControlWithGenericBase() {      InitializeComponent();    }  }  

VB.NET Code

 Public Class UserControlWithGenericBase    Inherits GenericBase(Of String)  End Class  

Silverlight

This workaround only applies to WPF applications.  Currently Silverlight does not support the x:TypeArguments property that is required in the deriving control's XAML root tag.

If you must have Silverlight controls that derive from a generic base class you have to do some extra work.  Basically you need to have an extra class in the middle so that the UserControl would derive from a non-generic class

Base class:  public class GenericBase<T> : UserControl

Middle class:  public class MiddleStringControl : GenericBase<String>

UserControl:  public class UserControlWithGenericBase : MiddleStringControl

Comments

Microsoft values your opinion about our products and documentation. In addition to your general feedback it is very helpful to understand:

  • How the above feature enables your workflow
  • What is missing from the above feature that would be helpful to you

Thank you for your feedback and have a great day,

Karl Shifflett

Visual Studio Cider Team