Until version 3.5 WPF still lacks many useful controls natively such as Calendar, Date Picker and Data Grid. On the other hand, the WPF Toolkit for WPF 3.5 provides these complementally:
In this post, we are going to talk about how to host the DataGrid control of the WPF Toolkit in a User Control and in turn a WPF Window.
Add the WPF Toolkit references first into the Revit WPF addin project:
Drag and drop the DataGrid control from the WPF Toolkit catalog as in the first illustration onto the User Control of our concern and create data classes and methods, set up DataGrid columns and prepare data providers:
Here are the data classes and their properties/methods:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RevitAddinCSWPF
{
public class Blog
{
public string Name { get; set; }
public Uri URL { get; set; }
public bool Public { get; set; }
public string Rate { get; set; }
}
public class DataProvider
{
public static string[] GetRatings() { return new string[] { "5", "4", "3", "2", "1" }; }
public static Blog[] CreateBlogs()
{
return new Blog[]
{
new Blog
{
Name = "Blog1",
URL = new Uri( "http://spiderinnet.typepad.com"),
Public = true,
Rate = GetRatings()[0]
},
new Blog
{
Name = "Blog2",
URL = new Uri( "http://spiderinnet1.typepad.com"),
Public = true,
Rate = GetRatings()[0]
},
new Blog
{
Name = "Blog3",
URL = new Uri( "http://spiderinnet2.typepad.com"),
Public = false,
Rate = GetRatings()[0]
},
new Blog
{
Name = "Blog4",
URL = new Uri( "http://spiderinnet3.typepad.com"),
Public = false,
Rate = GetRatings()[0]
},
};
}
}
}
Here are the data providers in the DataGrid Resources:
<Grid.Resources>
<ObjectDataProvider x:Key="DataProvider"
ObjectType="{x:Type local:DataProvider}"/>
<ObjectDataProvider x:Key="Blogs"
ObjectInstance="{StaticResource DataProvider}"
MethodName="CreateBlogs"/>
<ObjectDataProvider x:Key="Ratings"
ObjectInstance="{StaticResource DataProvider}"
MethodName="GetRatings"/>
</Grid.Resources>
Here is the content of the whole UserControl XMAL file to make the story complete:
<UserControl x:Class="RevitAddinCSWPF.UserControl5"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:local="clr-namespace:RevitAddinCSWPF"
Height="300" Width="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PresentationFramework.Luna;component/themes/luna.normalcolor.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.Resources>
<ObjectDataProvider x:Key="DataProvider"
ObjectType="{x:Type local:DataProvider}"/>
<ObjectDataProvider x:Key="Blogs"
ObjectInstance="{StaticResource DataProvider}"
MethodName="CreateBlogs"/>
<ObjectDataProvider x:Key="Ratings"
ObjectInstance="{StaticResource DataProvider}"
MethodName="GetRatings"/>
</Grid.Resources>
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Color="Azure" Offset="0.0" />
<GradientStop Color="Orchid" Offset="0.15" />
<GradientStop Color="Purple" Offset="0.25" />
<GradientStop Color="RosyBrown" Offset="0.5" />
<GradientStop Color="Purple" Offset="0.75" />
<GradientStop Color="Orchid" Offset="0.85" />
<GradientStop Color="Azure" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Button Height="27" HorizontalAlignment="Left" VerticalAlignment="Top" Width="24">TL</Button>
<Button Height="27" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="24">BL</Button>
<Button Height="27" HorizontalAlignment="Right" VerticalAlignment="Top" Width="24">TR</Button>
<Button Height="27" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="24">BR</Button>
<Button Name="button_Cancel" Margin="53,0,103,33" Height="27" Width="84"
VerticalAlignment="Bottom" Click="button_Cancel_Click">Cancel</Button>
<Button Name="button_OK" Margin="0,0,34,33" Height="27" Width="84"
HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="buttonOK_Click">OK</Button>
<CheckBox Margin="30,5.52,90,0" Name="checkBox1" VerticalAlignment="Top">CheckBox</CheckBox>
<CheckBox Margin="30,27,90,0" Name="checkBox2" VerticalAlignment="Top">CheckBox</CheckBox>
<CheckBox Margin="30,49,90,0" Name="checkBox3" VerticalAlignment="Top">CheckBox</CheckBox>
<RadioButton Margin="130,5,50,0" Name="radioButton1" VerticalAlignment="Top">RadioButton</RadioButton>
<RadioButton Margin="130,27,50,0" Name="radioButton2" VerticalAlignment="Top">RadioButton</RadioButton>
<RadioButton Margin="130,49,50,0" Name="radioButton3" VerticalAlignment="Top">RadioButton</RadioButton>
<my:DataGrid AutoGenerateColumns="False"
Margin="2,83,0,93"
Name="dataGrid1"
DataContext="{Binding Source={StaticResource Blogs}}"
ItemsSource="{Binding}">
<my:DataGrid.Columns>
<my:DataGridTextColumn Header="Name" Width="45"
Binding="{Binding Path=Name}"/>
<my:DataGridHyperlinkColumn Header="URL" Width="180"
Binding="{Binding Path=URL}"/>
<my:DataGridCheckBoxColumn Header="P" Width="20"
Binding="{Binding Path=Public}"/>
<my:DataGridComboBoxColumn Header="R" Width="40"
SelectedItemBinding="{Binding Path=Rate}"
ItemsSource="{Binding Source={StaticResource Ratings}}"
/>
</my:DataGrid.Columns>
</my:DataGrid>
</Grid>
</UserControl>
We’d better define a new External Command and create a new Ribbon button to trigger it. Here is the definition of the ExtCmd5:
#region Namespaces
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI.Events;
using Autodesk.Revit.Collections;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.Utility;
using RvtApplication = Autodesk.Revit.ApplicationServices.Application;
using RvtDocument = Autodesk.Revit.DB.Document;
#endregion
namespace RevitAddinCSWPF
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class ExtCmd5 : IExternalCommand
{
#region Cached Variables
private static ExternalCommandData _cachedCmdData;
public static UIApplication CachedUiApp
{
get
{
return _cachedCmdData.Application;
}
}
public static RvtApplication CachedApp
{
get
{
return CachedUiApp.Application;
}
}
public static RvtDocument CachedDoc
{
get
{
return CachedUiApp.ActiveUIDocument.Document;
}
}
#endregion
#region IExternalCommand Members
public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elemSet)
{
_cachedCmdData = cmdData;
try
{
//TODO: add your code below.
UserControl5 userControl = new UserControl5();
Window win = new Window();
win.Content = userControl;
win.Width = win.Height = double.NaN;
win.SizeToContent = SizeToContent.WidthAndHeight;
win.ShowInTaskbar = win.Topmost = true;
win.ResizeMode = ResizeMode.NoResize;
win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
win.HorizontalAlignment = win.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left;
win.VerticalAlignment = win.VerticalContentAlignment = VerticalAlignment.Top;
System.Windows.MessageBox.Show(string.Format("OKed? : {0}", win.ShowDialog()));
return Result.Succeeded;
}
catch (Exception ex)
{
msg = ex.ToString();
return Result.Failed;
}
}
#endregion
}
}
In addition, here is the extra button definition in the same CreateRibbonPanel method of the same External Application:
private RibbonPanel CreateRibbonPanel()
{
RibbonPanel panel = _cachedUiCtrApp.CreateRibbonPanel("RevitAddinCSWPF");
////Default button:
PushButtonData pbDataExtCmd = new PushButtonData("ExtCmd", "ExtCmd", Assembly.GetExecutingAssembly().Location, "RevitAddinCSWPF.ExtCmd");
PushButton pbExtCmd = panel.AddItem(pbDataExtCmd) as PushButton;
pbExtCmd.ToolTip = "ExtCmd";
pbExtCmd.LargeImage = BmpImageSource("RevitAddinCSWPF.Resources.ExtCmd32x32.bmp");
pbExtCmd.Image = BmpImageSource("RevitAddinCSWPF.Resources.ExtCmd16x16.bmp");
////More buttons:
…
…
PushButtonData pbDataExtCmd5 = new PushButtonData("ExtCmd5", "ExtCmd5", Assembly.GetExecutingAssembly().Location, "RevitAddinCSWPF.ExtCmd5");
PushButton pbExtCmd5 = panel.AddItem(pbDataExtCmd5) as PushButton;
pbExtCmd5.ToolTip = "ExtCmd5";
pbExtCmd5.LargeImage = BmpImageSource("RevitAddinCSWPF.Resources.ExtCmd32x32.bmp");
pbExtCmd5.Image = BmpImageSource("RevitAddinCSWPF.Resources.ExtCmd16x16.bmp");
return panel;
}
Now the project should build well and we are ready to give it a try immediately by pressing the F5 since Revit Addin Wizard (RevitAddinWizard) has already set up the debugging settings for us automatically.
If the ExtCmd5 ribbon button of the RevitAddinCSWPF ribbon panel is clicked, the WPF Window hosting the User Control and in turn hosting the WPF Toolkit DataGrid control will show up as expected:
In this small sample and the brief article, we introduced many WPF cool controls and core concepts actually:
• Data Grid Control
• DataGridTextColumn Sub Control
• DataGridHyperlinkColumn Sub Control
• DataGridCheckBoxColumn Sub Control
• DataGridComboBoxColumn Sub Control
• WPF User Control
• WPF Window
• Resources
• StaticResource
• ObjectDataProvider
• Data Binding
• DataContext
• ItemsSource
• SelectedItemBinding
• Etc.
Enjoy it!
More articles about WPF and Revit Addin/API can be expected. Please stay tuned.
RevitAddinWizard may provide a few coders to address some WPF usage cases in the near future.
Recent Comments