This walkthrough requires the following components installed on your workstation:
There are various data queries available in System Center 2012 Operations Manager (OM12) defined in the Microsoft.SystemCenter.Visualization.Library management pack. The Query that will be used in this example is GetAlertsForEntitiesQuery which returns all alerts in the management group. Detail on the specifics of this query is beyond the scope of this walkthrough. Only a brief explanation of the parameters passed and the data returned is required for this sample.
Only one parameter of GetAlertsForEntitiesQuery will be used in this example. The AlertProperties parameter identifies the set of properties that will be returned for each alert in the result set. Its properties are defined in the AlertType schema type which is part of Microsoft.SystemCenter.Visualization.OperationalDataTypes in Microsoft.SystemCenter.Visualization.Library. In this example the properties Name, Severity, and Priority are requested.
The result set returned is a collection of objects of the type IDataObject. Each element in the collection represents an alert. The property values can be accessed using:
instance[properyName].ToString()
Both a Silverlight and a WPF version of the AlertSummaryControl will be created in this solution. The Silverlight control, which is used by the web console, will be created first. The WPF version, which is used by the Operations Console, will then be created and will share the xaml and code behind from the Silverlight project.
The properties we selected to be returned for each alert are Name, Severity, and Priority. Below is a screen shot of the control that will be created to display this data. It groups the alerts by the Severity property and displays all three properties for the group of alerts in the selected severity group. The severity group is represented by a colored circle that contains the count of alerts in the group. When the circle is clicked the data grid displays the set of alerts with that severity level.
1.
using
System.ComponentModel;
2.
System.Collections.Generic;
public
class
AlertData : INotifyPropertyChanged
AlertItem
{
3.
string
Id {
get
;
set
; }
4.
Name {
5.
Severity {
6.
Priority {
7.
}
01.
private
_CriticalAlertCount;
02.
_WarningAlertCount;
03.
04.
List<AlertItem> _CriticalAlerts;
05.
List<AlertItem> _WarningAlerts;
06.
07.
CriticalAlertCount
08.
09.
return
_CriticalAlertCount; }
10.
11.
12.
if
(_CriticalAlertCount != value) {
13.
_CriticalAlertCount = value;
14.
OnPropertyChanged(
"CriticalAlertCount"
);
15.
16.
17.
18.
19.
WarningAlertCount
20.
21.
_WarningAlertCount; }
22.
23.
24.
(_WarningAlertCount != value) {
25.
_WarningAlertCount = value;
26.
"WarningAlertCount"
27.
28.
29.
30.
31.
List<AlertItem> CriticalAlerts
32.
33.
34.
this
._CriticalAlerts;
35.
36.
37.
38.
(_CriticalAlerts != value) {
39.
_CriticalAlerts = value;
40.
.OnPropertyChanged(
"CriticalAlerts"
41.
42.
43.
44.
45.
List<AlertItem> WarningAlerts
46.
47.
._WarningAlerts;}
48.
49.
50.
(_WarningAlerts != value) {
51.
_WarningAlerts = value;
52.
"WarningAlerts"
53.
54.
55.
56.
57.
event
PropertyChangedEventHandler PropertyChanged;
58.
59.
protected
void
propertyName)
60.
61.
(PropertyChanged !=
null
) {
62.
PropertyChanged(
,
new
PropertyChangedEventArgs(propertyName));
63.
64.
<UserControl x:Class=
"AlertSummaryControl.AlertControl"
xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d=
"http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc=
"http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable=
"d"
xmlns:data=
"clr-namespace:AlertSummaryControl"
HorizontalAlignment=
"Left"
VerticalAlignment=
"Top"
Background=
"White"
d:DesignHeight=
"300"
d:DesignWidth=
"600"
>
<UserControl.Resources>
<data:AlertData x:Key=
"alertDataInstance"
></data:AlertData>
</UserControl.Resources>
<StackPanel x:Name=
"LayoutRoot"
DataContext=
"{Binding Source={StaticResource alertDataInstance}}"
Orientation=
"Vertical"
Margin=
"20,20,20,20"
Width=
"560"
"spButtons"
"Horizontal"
<StackPanel Orientation=
Name=
"CriticalPanel"
<Grid Height=
"75"
"0,0,10,0"
<Border Background=
"Red"
CornerRadius=
"40"
<Button Content=
"{Binding Path=CriticalAlertCount}"
Click=
"btCritical_Click"
BorderThickness=
"0"
Foreground=
"Black"
BorderBrush=
"Transparent"
FontSize=
"16"
"49"
Height=
"22"
<Button.Template>
<ControlTemplate TargetType=
"Button"
<ContentPresenter VerticalAlignment=
"Center"
/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
<TextBlock x:Name=
"tbCriticalLabel"
FontWeight=
"Normal"
"12"
>Critical</TextBlock>
</StackPanel>
"WarningPanel"
"Yellow"
"{Binding Path=WarningAlertCount}"
"btWarning_Click"
"58"
"tbWarningLabel"
>Warning</TextBlock>
"tbMessage"
"20"
></TextBlock>
<Canvas x:Name=
"cvGrids"
</Canvas>
</UserControl>
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
partial
AlertControl : UserControl, INotifyPropertyChanged
AlertData alertData;
DataGrid criticalGrid;
DataGrid warningGrid;
AlertControl()
InitializeComponent();
.alertData = (AlertData)
.Resources[
];
criticalGrid =
DataGrid();
criticalGrid.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
criticalGrid.IsReadOnly =
true
criticalGrid.AutoGenerateColumns =
criticalGrid.Height = 200.0;
criticalGrid.Visibility = System.Windows.Visibility.Visible;
criticalGrid.ItemsSource =
.alertData.CriticalAlerts;
Binding criticalBinding =
Binding(
criticalGrid.SetBinding(DataGrid.ItemsSourceProperty, criticalBinding);
cvGrids.Children.Add(criticalGrid);
warningGrid =
warningGrid.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
warningGrid.IsReadOnly =
warningGrid.AutoGenerateColumns =
warningGrid.Height = 200.0;
warningGrid.Visibility = System.Windows.Visibility.Collapsed;
warningGrid.ItemsSource =
.alertData.WarningAlerts;
Binding warningBinding =
warningGrid.SetBinding(DataGrid.ItemsSourceProperty, warningBinding);
cvGrids.Children.Add(warningGrid);
.tbCriticalLabel.FontWeight = FontWeights.Bold;
)
btCritical_Click(
object
sender, RoutedEventArgs e)
.criticalGrid.Visibility = System.Windows.Visibility.Visible;
.warningGrid.Visibility = System.Windows.Visibility.Collapsed;
.tbWarningLabel.FontWeight = FontWeights.Normal;
.criticalGrid.Focus();
btWarning_Click(
.warningGrid.Visibility = System.Windows.Visibility.Visible;
.criticalGrid.Visibility = System.Windows.Visibility.Collapsed;
.tbWarningLabel.FontWeight = FontWeights.Bold;
.tbCriticalLabel.FontWeight = FontWeights.Normal;
.warningGrid.Focus();
AlertSummaryControl.AlertControl alertControl =
AlertSummaryControl.AlertControl();
LayoutRoot.Children.Add(alertControl);
"Test"
"button1"
"23"
"button1_Click"
MainPage : UserControl
AlertSummaryControl.AlertControl alertControl;
MainPage()
alertControl =
button1_Click(
List<AlertSummaryControl.AlertItem> criticalAlerts =
List<AlertSummaryControl.AlertItem>();
for
(
int
i = 1; i <= 5; i++)
AlertSummaryControl.AlertItem criticalAlert =
AlertSummaryControl.AlertItem();
criticalAlert.Id =
"Id #"
+ i.ToString();
criticalAlert.Name =
"Name"
criticalAlert.Priority =
"Priority"
criticalAlert.Severity =
"Critical"
criticalAlerts.Add(criticalAlert);
alertControl.alertData.CriticalAlerts = criticalAlerts;
alertControl.alertData.CriticalAlertCount = criticalAlerts.Count.ToString();
List<AlertSummaryControl.AlertItem> warningAlerts =
i = 1; i <= 10; i++)
AlertSummaryControl.AlertItem warningAlert =
warningAlert.Id =
"Id"
warningAlert.Name =
warningAlert.Priority =
warningAlert.Severity =
"Warning"
warningAlerts.Add(warningAlert);
alertControl.alertData.WarningAlerts = warningAlerts;
alertControl.alertData.WarningAlertCount = warningAlerts.Count.ToString();
<Resources>
<Assembly
ID=
"SilverlightAssembly"
QualifiedName=
"AlertSummarySilverlight, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
FileName=
"AlertSummarySilverlight.dll"
Accessibility=
"Public"
HasNullStream=
"false"
"WPFAssembly"
"AlertSummaryWPF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"AlertSummaryWPF.dll"
</Resources>
<Categories>
<Category
"SilverlightCategory"
Target=
Value=
"Visualization!Microsoft.SystemCenter.Visualization.SilverlightComponentAssembly"
"WPFCategory"
"Visualization!Microsoft.SystemCenter.Visualization.WpfComponentAssembly"
</Categories>
Note: You may need to add a reference to Microsoft.SystemCenter.Visualization.Library with the alias Visualization to your management pack project.
<Presentation>
<ComponentTypes>
<ComponentType ID=
"AlertSummaryControl"
"AlertSummaryHost"
</ComponentTypes>
</Presentation>
<ComponentImplementations>
<ComponentImplementation
TypeId=
"AlertSummaryControlImplementation"
Platform=
"All"
<Unit>
<ContractFactory>AlertSummaryControl.AlertControl</ContractFactory>
</Unit>
</ComponentImplementation>
</ComponentImplementations>
"AlertSummaryImplementation"
<Composite>
<Component TypeId=
"Visualization!Microsoft.SystemCenter.Visualization.ComponentContainer"
<Binding PropertyId=
"Visual"
</Component>
</Binding>
</Composite>
<ComponentReferences>
<ComponentReference
"AlertSummaryReference"
TypeID=
Parent=
"SC!Microsoft.SystemCenter.Monitoring.ViewFolder.Root"
</ComponentReferences>
Microsoft.EnterpriseManagement.CompositionEngine;
Presentation = Microsoft.EnterpriseManagement.Presentation.DataAccess;
IEnumerable<Presentation.IDataObject> _items;
IEnumerable<Presentation.IDataObject> Items
._items;
(value !=
_items = value;
"Items"
Microsoft.EnterpriseManagement.Presentation.DataAccess;
.alertData.Items;
.alertData.Items = value;
Presentation.DynamicObservableDictionaryDataObjectCollection collection = value
as
Presentation.DynamicObservableDictionaryDataObjectCollection;
(collection !=
collection.CollectionChanged +=
System.Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
delegate
ProcessAlerts_Delegate();
collection_CollectionChanged(
sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
.Dispatcher.BeginInvoke(
ProcessAlerts_Delegate(ProcessAlerts),
ProcessAlerts()
List<AlertItem> criticalAlerts =
List<AlertItem>();
List<AlertItem> warningAlerts =
lock
.alertData.Items)
foreach
(var alert
in
.alertData.Items.ToArray())
try
DynamicObservableDictionaryDataObject dataObject = (DynamicObservableDictionaryDataObject)alert;
AlertItem newItem =
AlertItem()
Id = dataObject[
].ToString(),
Name = dataObject[
Severity = dataObject[
"Severity"
Priority = dataObject[
].ToString()
};
switch
(dataObject[
].ToString())
case
:
criticalAlerts.Add(newItem);
break
warningAlerts.Add(newItem);
catch
(Exception ex)
.alertData.CriticalAlertCount = criticalAlerts.Count.ToString();
.alertData.CriticalAlerts = criticalAlerts;
.alertData.WarningAlertCount = warningAlerts.Count.ToString();
.alertData.WarningAlerts = warningAlerts;
<Property
Type=
"xsd://Microsoft.SystemCenter.Visualization.Library!Microsoft.SystemCenter.Visualization.DataProvider/BaseManagedEntity[]"
BindingDirection=
"In"
</ComponentType>
<Property Name=
Direction=
<Reference>$Property/Items$</Reference>
</Property>
<Reference>$Variable/MyVar$</Reference>
<Variable Id=
"MyVar"
"Objects"
"Visualization!GetAlertsForEntitiesQuery"
"Output"
"AlertProperties"
<ComplexValueCollection Type=
"xsd://Microsoft.SystemCenter.Visualization.Library!Microsoft.SystemCenter.Visualization.DataSourceTypes/ValueDefinition[]"
<ComplexValue Type=
"xsd://Microsoft.SystemCenter.Visualization.Library!Microsoft.SystemCenter.Visualization.DataSourceTypes/ValueDefinition"
"OutputPropertyName"
<SimpleValue Type=
"xsd://string"
"XPath"
"$Object/Property[Name='Name']$"
"DisplayName"
"$NONE$"
</ComplexValue>
"$Object/Property[Name='Severity']$"
"$Object/Property[Name='Priority']$"
</ComplexValueCollection>
<Folders>
<Folder
"WalkthroughsFolder"
ParentFolder=
"Config!Microsoft.SystemCenter.Visualization.WidgetViewTemplateRoot"
</Folders>
<LanguagePacks>
<LanguagePack ID=
"ENU"
IsDefault=
"true"
<DisplayStrings>
<DisplayString ElementID=
<Name>Walkthroughs Folder</Name>
</DisplayString>
<Name>Alert Summary Widget</Name>
</DisplayStrings>
</LanguagePack>
</LanguagePacks>
<TypeDefinitions>
<SchemaTypes>
<SchemaType ID=
"AlertSummarySchema"
"Internal"
<xsd:complexType name=
"Configuration"
<xsd:sequence minOccurs=
"1"
maxOccurs=
<xsd:element name=
"notUsed1"
type=
"xsd:boolean"
minOccurs=
</xsd:sequence>
</xsd:complexType>
"Personalization"
"notUsed2"
</SchemaType>
</SchemaTypes>
</TypeDefinitions>
<ComponentBehaviors>
<ComponentBehavior
"AlertSummaryComponentBehavior"
BehaviorTypeId=
"Visualization!Microsoft.SystemCenter.Visualization.PersonalizeBehavior"
ComponentTypeId=
<Bindings>
"EnableImplicitChanges"
"xsd://boolean"
"False"
"ConfigurationDataType"
<SimpleValue
"xsd://AlertSummaryPack!AlertSummarySchema/Configuration"
"PersonalizationDataType"
"xsd://AlertSummaryPack!AlertSummarySchema/Personalization"
</Bindings>
</ComponentBehavior>
</ComponentBehaviors>
<ManagementPackFragment xmlns:xsd=
"http://www.w3.org/2001/XMLSchema"
"AlertSummaryConfigPages"
"Config!Microsoft.SystemCenter.Visualization.CustomConfigurationPages"
"component://AlertSummaryPack!AlertSummaryHost"
"Config!Microsoft.SystemCenter.Visualization.CustomPages"
</ManagementPackFragment>
"AlertSummaryControl.Configuration"
xmlns:sdk=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
"199"
"550"
Loaded=
"UserControl_Loaded"
<Grid x:Name=
"132"
"489"
<TextBlock
Text=
"Enter Max Count of Alerts To Display Per Severity Level."
"21,16,0,0"
"13"
"Bold"
"Maximum Critical Alerts"
"21,48,0,0"
"151"
<TextBox
"32"
"202,48,0,0"
"tbMaxCriticalAlerts"
TextChanged=
"tbMaxCriticalAlerts_TextChanged"
"Maximum Warning Alerts"
"21,80,0,0"
"202,80,0,0"
"tbMaxWarningAlerts"
"tbMaxWarningAlerts_TextChanged"
Configuration : UserControl, INotifyPropertyChanged
_maxCritical;
_maxWarning;
MaxCritical
._maxCritical = value;
.tbMaxCriticalAlerts.Text = value.ToString();
"MaxCritical"
MaxWarning
._maxWarning = value;
.tbMaxWarningAlerts.Text = value.ToString();
"MaxWarning"
Configuration()
tbMaxCriticalAlerts_TextChanged(
sender, TextChangedEventArgs e)
value;
.TryParse(
.tbMaxCriticalAlerts.Text,
out
value))
.MaxCritical = value;
tbMaxWarningAlerts_TextChanged(
.tbMaxWarningAlerts.Text,
.MaxWarning = value;
UserControl_Loaded(
"AlertSummaryControl.Personalization"
"142"
"337"
"327"
"Select Severity Types to be Displayed"
<CheckBox
"cbCritical"
"21,48,145,61"
Checked=
"cbCritical_Checked"
Unchecked=
"Critical Alerts"
"41,48,0,0"
"cbWarning"
"21,80,145,29"
"cbWarning_Checked"
"Warning Alerts"
"41,80,0,0"
System.ComponentModel.Composition;
Personalization : UserControl, INotifyPropertyChanged
bool
_criticalEnabled;
_warningEnabled;
CriticalEnabled
._criticalEnabled = value;
.cbCritical.IsChecked = value;
"CriticalEnabled"
WarningEnabled
._warningEnabled = value;
.cbWarning.IsChecked = value;
"WarningEnabled"
Personalization()
cbCritical_Checked(
.CriticalEnabled =
.cbCritical.IsChecked.GetValueOrDefault();
cbWarning_Checked(
.WarningEnabled =
.cbWarning.IsChecked.GetValueOrDefault();
_maxCritical = 10;
_maxWarning = 10;
(_maxCritical != value)
.collection_CollectionChanged(
(_maxWarning != value)
.CriticalPanel.Visibility == System.Windows.Visibility.Visible;
.CriticalPanel.Visibility =
value ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
.WarningPanel.Visibility == System.Windows.Visibility.Visible;
.WarningPanel.Visibility =
.Items ==
||
.alertData ==
.alertData.Items ==
criticalCount = 0;
warningCount = 0;
DynamicObservableDictionaryDataObject dataObject =
(DynamicObservableDictionaryDataObject)alert;
criticalCount++;
(criticalCount <= _maxCritical)
warningCount++;
(warningCount <= _maxWarning)
"MaxCritical_widget"
"xsd:int"
"MaxCritical_uc"
"xsd://integer"
<ComponentImplementation TypeId=
<Reference>$Property/MaxCritical_uc$</Reference>
<Reference>$Property/MaxCritical_widget$</Reference>
"ConfigurationPage"
"MaxCritical_cPage"
"xsd://int"
<ContractFactory>AlertSummaryControl.Configuration</ContractFactory>
"Both"
<Reference>$Property/MaxCritical_cPage$</Reference>
<Reference>$Property/Data/MaxCritical_widget$</Reference>
"MaxWarning_cPage"
"PersonalizationPage"
"CriticalEnabled_pPage"
"WarningEnabled_pPage"
"MaxWarning_widget"
"CriticalEnabled_widget"
"WarningEnabled_widget"
"MaxWarning_uc"
"WarningEnabled_uc"
"CriticalEnabled_uc"
<Reference>$Property/MaxWarning_uc$</Reference>
<Reference>$Property/CriticalEnabled_uc$</Reference>
<Reference>$Property/WarningEnabled_uc$</Reference>
<Reference>$Property/CriticalEnabled_widget$</Reference>
<Reference>$Property/WarningEnabled_widget$</Reference>
<Reference>$Property/MaxWarning_widget$</Reference>
"ConfigurationPageImplementation"
<Reference>$Property/MaxWarning_cPage$</Reference>
"PersonalizationPageImplementation"
<ContractFactory>AlertSummaryControl.Personalization</ContractFactory>
<Reference>$Property/CriticalEnabled_pPage$</Reference>
<Reference>$Property/WarningEnabled_pPage$</Reference>
"Pages"
"Visualization!Microsoft.SystemCenter.Visualization.WizardRegularPage"
"StepId"
"Max Alerts Displayed"
"Title"
"IsValid"
"True"
"FinishButtonText"
"Finish"
"Content"
<Reference>$Property/Data/MaxWarning_widget$</Reference>
"AlertSummaryWidgetPersonalizationPages"
" Config!Microsoft.SystemCenter.Visualization.CustomPersonalizationPages"
"component://AlertSummaryPackRMS!AlertSummaryHost"
" Config!Microsoft.SystemCenter.Visualization.CustomPages"
"Alert Severities"
<Reference>$Property/Data/CriticalEnabled_widget$</Reference>
<Reference>$Property/Data/WarningEnabled_widget$</Reference>
This article has been highlighted in this week's Top Contributors of the Week Awards - blogs.technet.com/.../top-contributors.aspx
hi,
Is it possible to create a widget from two projects( Silverlight and WPF) without linking their codes (no adding as link from silverlight to WPF)? if it's possible then how do i link resources files from 2 projects to the Management pack ( i can't find the wpf.dll file any where? Please advise.
Thank you
Nice writeup. 44 steps though? Across VS, SCOM, and manual XML editing? Is this something you'd actually expect a mortal to a) figure out and b) implement correctly?
im realy thankful for your beneficial article.ive read your document;it was asset to me and i could make a dashboard with its help, but ive confronted some complications.when i change the ID "alert summary component type", nothing is represented by my dashboard. furthermore whenever I make a change inside WPF, I cant see it in the Operation Console.
could you possibly help me with that.
I followed your instructions step by step, but I have one problem:
The problem is that in the Console, the Config and Personalization Pages are not showing, they appear blank, but the widget is showing OK. Meanwhile, in the Web Console, Config and Personalization Pages appear OK, but the widget is not appearing, it remains blank.
It's a little weird, and I don't know where the problem can be.
I also tried to import your sample project in SCOM, but I got the same result.
Any help would be appreciated.
Thank you in advance.