Home > Articles > Programming > Windows Programming

Events in XAML-Based Applications

Matteo Slaviero explores how events management in XAML-based applications changes due to Binding technology and the MVVM pattern. Learn how to work with the ICommand interface, RoutedUICommands, and Triggers.
Like this article? We recommend

Introduction

As a developer, I began to use the .NET Framework from its very beginning. It was 2002 when I started to play with .NET Framework 1.0 and Visual Studio .NET 2002. In those years, life was very hard for developers using Microsoft Technologies. Visual Basic 6.0 was beginning to show its limits, and Visual C++ 4.0 was considered too complex and not productive enough for businesses. The Java programming language was almost always the preferred choice for companies that were beginning to focus on software development as an important factor in competitiveness.

The situation began to change when experts started to recognize the innovative architecture of ASP.NET technology and the power of server controls. In those years, business applications began to move to the Web, giving this approach a lot of advantages in term of deployment of applications and centralization (on the server) of business information. Previously the Web was considered primarily a platform for text and images, and using it for data management was a big challenge. ASP.NET was the Microsoft response to this challenge. The idea of the page's postback was the first attempt to apply the data-centric behaviors of desktop applications to the content-oriented characteristics of the web platform.

With ASP.NET, when a user interacts with some controls on the page, the page is posted back to the server, and some event handler is executed. If code inside the handler modifies the state of the page, an updated version of that page is returned to the user. The intent was to reproduce the behavior of WinForm applications, where each user action generates an event that invokes event handlers installed for it. Even if the idea behind the page's postback had been successful for the transition from websites to web applications, the limits imposed by the HTML standard sometimes forced developers to perform real stunts to implement some functionalities. (Remember that HTML was designed with content in mind!)

Life became easier with the advent of AJAX and JavaScript libraries in general, even though they weren't always easy to implement. On the other hand, the growth of multimedia contents over time also increased the expectations of the desktop user. Along came Windows Presentation Foundation (WPF) and Silverlight (actually in its fourth version). In my opinion, this change represented a real milestone in relation to the new multimedia requirements; above all, this was a step toward further integration between desktop and data-centric web applications. In general, it seems destined to be the all-in-one technology for the presentation layers of desktop, web, and mobile applications.

As a WinForm and ASP.NET developer, I was very excited when I started to understand the benefits introduced by the Extensible Application Markup Language (XAML), both when developing desktop applications (using WPF) and in web applications (using Silverlight).

WPF and Silverlight architectures are based mainly on the DependencyObject class, a class from which all the UIElement classes (which controls classes) and animation-related classes derive. The introduction of DependencyObjects brings a lot of new and interesting features, the Binding subsystem being the most important when dealing with data management.

Binding in XAML applications deeply changed the way in which software has to be designed. The concept of n-tier architecture, very common in pre-XAML applications, is being replaced by patterns like Model-View-ViewModel (MVVM), based on a clear distinction between the user interface (the View) and the data objects (the Model). The need for it derives from the new graphics capabilities of XAML-based applications. The design of the user interface with XAML has become a job for graphic designers rather than software developers. Designers feel comfortable with fonts, palettes, and animations, but in general they prefer to have nothing to do with code; they prefer Expression Blend to Visual Studio. So the separation of XAML from business logic code has become an important aspect when architecting a new application.

While the separation of the Model from the View doesn't require new concepts for developers (a conventional class with properties that describe the purpose of the data object, sometimes referred as "plain old CLR object" or POCO, is enough as the source for data binding), implementing all the functionality related to the user interaction with the View requires some new concepts that are the subject of this article.

The ICommand Interface

Traditionally, in WinForm and ASP.NET programming, for each user action we develop an event handler that we install for the event raised. Normally, we put the event handler's code in the code behind a Windows Form or ASP.NET web page, but this approach is inadequate for XAML-based applications. It brings a strong coupling between the user interface and the code behind our solution, thus diminishing the power of XAML.

We need to separate the XAML code from all the other code and use Binding as the "gateway" between the data, actions on the data, and the presentation layer. For this to happen, we need to try our best to use properties rather than methods. In fact, only properties can act as source of Binding.

A good approach is to use the Command and CommandParameter properties defined for all the controls that permit a mouse click. Command and CommandParameter are defined in the ButtonBase, MenuItem, and Hyperlink classes. Command is a property that implements the ICommand interface, defined as follows:

bool CanExecute(object parameter)
void Execute(object parameter)
event EventHandler CanExecuteChanged

The CanExecute(...) method permits you to check whether the command can be executed. As input argument, it accepts the value assigned to the CommandParameter property. It has a return value of type Boolean. When the method returns true, the command can be executed. When it returns false, it cannot. Normally, in this case, the control to which the command belongs (very often a Button) appears disabled.

The Execute(...) method is where we write the code that will be executed when the command is invoked. Even in this case, the value assigned to the CommandParameter property is made accessible to us as the method's argument.

The CanExecuteChanged event tracks the availability of the command. The CanExecute(...) method is invoked when the command is created. If something changes during the lifetime of its owner, the CanExecuteChanged event is fired and the CanExecute(...) method is reevaluated, thus updating the state of the owner. Note that you don't need to assign an event handler to that event; it's automatically installed by the owner during its creation, and you only invoke it when needed.

Let's look at an example. Suppose that we have a Button that performs some action when data is available. We can build our command as shown in Listing 1.

Listing 1—ICommand interface implementation.

public class ProcessDataCommand:ICommand
    {
        bool _areDataAvailable;
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// State if data are available
        /// </summary>

        public bool AreDataAvailable
        {
            get {return _areDataAvailable;}
            set {_areDataAvailable = value;
                if (CanExecuteChanged != null) CanExecuteChanged(this,new EventArgs()); }
        }

        /// <summary>
        /// CanExecute method
        /// </summary>
        /// <returns></returns>
        public bool CanExecute(object parameter)
        {
            return AreDataAvailable;
        }

        /// <summary>

        /// Execute method
        /// </summary>
        public void Execute(object parameter)
        {
            DoSomething(parameter);
        }
    }

ProcessDataCommand defines a property, AreDataAvailable, which tracks data availability. When the ProcessDataCommand object is created, its value is set to false, so the Button appears disabled. When data reaches the application, we set AreDataAvailable to true. This causes the CanExecute(...) method to reevaluate. In this case, the value returned by the method is true, so the Button will be enabled.

This automatic refresh of the Button's state happens only if we use the "magic wand" of Binding. Our XAML code should be something like Listing 2, where OurDemoApplication is the namespace given to our application.

Listing 2—ICommand-derived object usage.

      <UserControl
            ...
            ...
    xmlns:local="clr-namespace:OurDemoApplication">

    <UserControl.Resources>

        <local:ProcessDataCommand x:Key="ProcessDataCommand" />
    </UserControl.Resources>

    <Button Content="Process Data"
            Command="{Binding Source={StaticResource ProcessDataCommand}}" />

Routed Commands

If you're using WPF instead of Silverlight, you have more options. As a source of Binding, you can use objects of type RoutedUICommand or RoutedCommand (the RoutedUICommand class simply adds the Text property to the base RoutedCommand class). RoutedUICommand implements the ICommand interface, but in this case the .NET Framework doesn't allow you to override the CanExecute(...) and Execute(...) methods, so you have to use the CommandBindings property of the Window object, as shown in Listing 3.

Listing 3—RoutedUICommand usage.

    <Window.Resources>
        <RoutedUICommand x:Key="CustomCommand" Text="Process" />
    </Window.Resources>

    <Window.CommandBindings>

        <CommandBinding Command="{StaticResource CustomCommand}"
               CanExecute=" CustomCommand_CanExecute" Executed=" CustomCommand_Executed" />
    </Window.CommandBindings>

    <Window.InputBindings>
        <KeyBinding Command="{StaticResource CustomCommand}" Key="P" Modifiers="Alt" />
    </Window.InputBindings>

    <Grid DataContext="{StaticResource CustomCommand}">

        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Menu>
            <MenuItem Header = "{Binding Path=Text}" Command="{Binding}" Grid.Row="0" />
        </Menu>

        <Button Content = "{Binding Path=Text}" Command="{Binding}" Grid.Row="1" />

    </Grid>

In Listing 3 we have created an object of type RoutedUICommand in the Resource section of the Window object, and we added it to the Window's CommandBinding collection. At this stage, we declare the two handlers for the CanExecute(...) and Execute(...) methods.

RoutedUICommand also allows us to invoke a command by using the keyboard. To do so, in the InputBindings collection of the Window object, we've added a KeyBinding object. By pressing Alt-P on the keyboard, the command is invoked as if we had clicked it.

Finally, we've declared Button and MenuItem objects and bound the new command to them. Now we're able to invoke the Execute(...) method by clicking the Button, clicking the MenuItem, or pressing Alt-P on the keyboard.

RoutedUICommands are so important in WPF that the PresentationCore.dll and PresentationFramework.dll assemblies define a complete set of prebuilt RoutedUICommands. They're grouped under five distinct classes:

  • ApplicationCommands
  • ComponentCommands
  • MediaCommands
  • NavigationCommands
  • EditingCommands

Listing 4 shows how to add a "Close" RoutedUICommand to the CommandBindings collection of a Window object.

Listing 4—Predefined RoutedUICommand usage.

    <Window.CommandBindings>
        <CommandBinding Command="Close"
CanExecute="Close_CanExecute" Executed="Close_Executed" />
    </Window.CommandBindings>

    <Button Content = "Close" Command="Close" />

Very often, RoutedUICommands are considered the preferred choice when working with WPF. Their main disadvantage is that they can't bring a full separation of XAML code from the business logic's code. Event handlers need to be implemented in the code behind a WPF control; we can't move them into a ViewModel class.

So why are they preferred? One reason is surely the ease of their implementation, as we've seen in Listing 4. But the main reason relies on the different nature of ICommand-derived objects and RoutedUICommands. These last, in fact, are specific to XAML-based applications, and they were introduced in order to take full advantage of the tree-based relationship between controls disposition. When we install an event handler for a control, all the controls inside its elements tree are able to fire the same event. We say that the event has been routed from an element to its container.

This behavior very often represents not an optimization, but a real need. Suppose we have a Button with its Content property set to a simple TextBlock object. Then suppose that we want to perform some tasks when the user moves the mouse inside the button surface. What really is the button surface? Traditionally we consider a button a clickable rectangle with a caption inside it. In XAML-based applications, this is no longer true. The content that we see inside the rectangle is an object itself. In our example, it's a TextBlock object. TextBlock derives from FrameworkElement, and then from UIElement. A portion of the rectangle's visible area therefore belongs to it, and it has its own MouseMove event, too. If we move the mouse inside the TextBlock area, it's the TextBlock, not the Button, that receives the MouseMove event. So how do we obtain the same result for legacy Buttons? The response is to route the TextBlock's MouseMove event to the Button. Consider the example in Listing 5, where Button_MouseMove is defined as in Listing 6.

Listing 5—Routed events in XAML.

<Button x:Name="MyButton" MouseMove="Button_MouseMove" >
    <Button.Content>
        <TextBlock Text="Click this Button !" />
    </Button.Content>
</Button>

Listing 6—Routed events—code behind.

private void Button_MouseMove(object sender, MouseEventArgs e)
{
Title = e.Source.ToString();
}

To the Title property of the Window is assigned the type of the object source of the event. When we move the mouse inside the region defined by the Button borders, the Title of the Window displays the value "System.Windows.Controls.Button" unless we enter the TextBlock region. In this case, the Title becomes "System.Windows.Controls.TextBlock". The TextBlock has routed the event to the Button. To prove this is the case, we add an event handler to the TextBlock, as shown in Listing 7, where the TextBlock_MouseMove event is given by Listing 8.

Listing 7—Prevent routing in routed events—XAML.

<Button x:Name="MyButton" MouseMove="Button_MouseMove" >
    <Button.Content>
        <TextBlock Text="Click this Button !" MouseMove="TextBlock_MouseMove" />
    </Button.Content>
</Button>

Listing 8—Prevent routing in routed events—code behind part 1.

private void TextBlock_MouseMove(object sender, MouseEventArgs e)
{
   Title = "";
}

Nothing changes. Why? After that, the TextBlock_MouseMove event is executed, the event is routed to the Button, and so the Button_MouseMove is fired, bringing us to a situation identical to the previous one. To prevent this from happening, we need to instruct the TextBlock_MouseMove event handler that its job is complete, and nothing has to be done. In other words, we need to prevent the event from being routed. We do this by using the Handled property of the argument. The Handled property is a Boolean property defined in the RoutedEventArgs class, so it's available to all the routed events. Each of them, in fact, has as its second parameter an object whose class is given by or that derives from RoutedEventArgs. We rewrite the event handler as in Listing 9.

Listing 9—Prevent routing in routed events—code behind part 2.

private void TextBlock_MouseMove(object sender, MouseEventArgs e)
{
    Title = "";
    e.Handled = true;
}

In this case, when the mouse pointer moves inside the TextBlock area, the Window's Title disappears, as we expected.

Grouping Events

Another common approach when using routed events relies on the possibility of installing an event handler on a container when two or more controls inside it are able to fire the same event. Suppose that we have two distinct Buttons with content given by a TextBlock, and we want to manage the MouseMove event in both of them. We can group the two buttons; for example, in a StackPanel, and install the event handler on it. StackPanel derives indirectly from the UIElement class, so it supports the MouseMove event as the Button and TextBlock classes do. Take a look at the example in Listing 10.

Listing 10—Install routed events for multiple controls.

<StackPanel MouseMove="Button_MouseMove">

    <Button>
        <Button.Content>
            <TextBlock Text="Click this Button !" />
        </Button.Content>

    </Button>

    <Button>
        <Button.Content>
            <TextBlock Text="Click this Button !" />
        </Button.Content>
    </Button>

</StackPanel>

When we move the mouse pointer inside one of the two TextBlock objects, the event is routed to its container (the Button to which the TextBlock belongs); at the same time, it routes the event to the StackPanel. In this case, the source of the event is the TextBlock that has the mouse pointer moving inside its surface, so the window will display the value "System.Windows.Controls.TextBlock" as the title. If we move the mouse pointer inside one of the two buttons, the Window's title will became "System.Windows.Controls.Button", as expected.

But what if we need to install event handlers for the Click events of the two Buttons? The Click event, as for the Command property, doesn't belong to the UIElement class or the FrameworkElement class. It's defined in the ButtonBase class, so StackPanel doesn't have it. If we have some reason not to bind the two Command properties of the two Buttons to a single object that implements the ICommand interface, we can use Styles instead. As you probably know, XAML-based applications permit you to group common properties' values into a single Style class that then can be applied to controls. The Style class can also group events by using the EventSetter class. In this case, our previous example changes as shown in Listing 11.

Listing 11—EventSetter usage.

<Window.Resources>
    <Style x:Key="ButtonStyle"  TargetType="Button">
        <EventSetter Event="Click"  Handler="Button_Click" />
    </Style>
</Window.Resources>

<StackPanel>

    <Button Style="{StaticResource ButtonStyle}">
        <Button.Content>
            <TextBlock Text="Click this Button !" />
        </Button.Content>
    </Button>

    <Button Style="{StaticResource ButtonStyle}">
        <Button.Content>
            <TextBlock Text="Click this Button !" />
        </Button.Content>
    </Button>

</StackPanel>

We've created a Style, with the key given by ButtonStyle, and we used the EventSetter class to install the Button_Click event handler to the Click event. Then we added the created Style to the Style property of the two buttons.

Using Triggers

Styles not only permit us to group common related properties and events; they also allow controls to which the Style is applied to modify the state of the Style when some condition occurs. This is done with Triggers. Even if they're not strictly events (in fact, they're related to the user interface design), I would like to end this article with them because, prior to XAML, what Triggers do was possible only with events.

Suppose you want to change the Foreground property of a Button when the mouse pointer hovers over it. Traditionally, we would install an event handler for the MouseOver event of the Button and write some C# or Visual Basic .NET code. In WPF applications, we can use a Trigger instead, as shown in Listing 12.

Listing 12—WPF's Trigger usage.

<Window.Resources>
    <Style x:Key="ButtonStyle"  TargetType="Button">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">

                <Setter Property="Foreground" Value="Beige" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Button Style="{StaticResource ButtonStyle}">

      <Button.Content>
           <TextBlock Text="Click this Button !" />
   </Button.Content>
</Button>

In this example, the IsMouseOver property is monitored by the Trigger. When it assumes the value True, the Setter is applied. When its value changes back to False, the Setter is removed. We're synchronizing the IsMouseOver property of the Button with its Foreground property without writing a line of C# or Visual Basic .NET code. Multiple Trigger conditions can be applied. In this case, we need to use the MultiTrigger object. Suppose that we want to change the Foreground color of the Button when the mouse is over it, and the Button is the default button of the Window. We need to modify the previous example as in Listing 13.

Listing 13—WPF's MultiTrigger usage.

<Window.Resources>
    <Style x:Key="ButtonStyle"  TargetType="Button">
        <Style.Triggers>
            <MultiTrigger>

                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver" Value="True" />
                    <Condition Property="IsDefault" Value="True" />
                </MultiTrigger.Conditions>
                <Setter Property="Foreground" Value="Beige" />
            </MultiTrigger>

        </Style.Triggers>
    </Style>
</Window.Resources>

  <Button Style="{StaticResource ButtonStyle}">
     <Button.Content>
         <TextBlock Text="Click this Button !" />

     </Button.Content>
  </Button>

We've defined a MultiTrigger object and set two conditions for it: the mouse pointer had to be over the Button, and the Button needed to be the default button of the Window.

The Triggers that we've seen so far are property-based. The Trigger condition is always applied to properties of some controls. With Triggers it's possible to monitor the data's current values, too. To do so, we need to use DataTriggers and MultiDataTriggers. In this case, the Property attribute is replaced by a Binding to the data object to monitor.

Suppose that we have a ViewModel class that exposes a List<String> object to the View. Then suppose that we have a Button that performs some operation on it and we want to disable the Button if the list is empty. We can write something like Listing 14.

Listing 14—WPF's DataTrigger usage.

  <Window
        ...
        ...
xmlns:local="clr-namespace:OurDemoApplication">

<Window.Resources>

    <local:VmSomeData x:Key="SomeData" />

    <Style x:Key="ButtonStyle"  TargetType="Button">
        <Style.Triggers>
            <DataTrigger Binding="{Binding
Source={StaticResource SomeData}, Path=MyData.Count}" Value="0">
                <Setter Property="IsEnabled" Value="False" />
            </DataTrigger>
        </Style.Triggers>

    </Style>

</Window.Resources>

<Button Style="{StaticResource ButtonStyle}">
      <Button.Content>
               <TextBlock Text="Click this Button !" />
   </Button.Content>

</Button>

In the resource section of the Window, we've declared a static resource related to the ViewModel class (VmSomeData). After that, we created a Style object and added a DataTrigger to its TriggersCollection. The DataTrigger monitors the Count property of the MyData (the List<String>) object. When the value is 0, the Setter puts the Button into a disabled state. If we add some data to the list, the Button becomes enabled again.

Another type of Trigger exists. The EventTrigger monitors changes in event conditions. It's used in XAML-based animations, and I leave you on your own to investigate how it works.

Note that, while WPF has full support for Triggers, using Triggers in Silverlight requires further steps. We need to add to our solution a reference to the System.Windows.Interactivity.dll assembly. It's part of the Expression Blend SDK. Triggers in XAML are very different from Triggers in WPF. To use them, we need to create a TriggerAction<T> derived class, where T is the type of the object to which the Trigger applies. Then we use it in our XAML code. We can rewrite Listing 12 as shown in Listing 15.

Listing 15—Silverlight's Trigger usage—XAML.

  <UserControl
        ...
        ...
            xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity ">

<Button Content="Click this Button !">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseMove">

            <local:MouseMoveTriggerAction />
        </i:EventTrigger>
        <i:EventTrigger EventName="MouseLeave">
            <local:MouseLeaveTriggerAction />
        </i:EventTrigger>
    </i:Interaction.Triggers>

</Button>

We've associated two Trigger conditions to the Button. The first is executed when the mouse pointer is over the Button, and the second when it leaves the Button. We need to manage the two cases (MouseMove and MouseLeave), because Triggers in Silverlight don't benefit from synchronization. The MouseMoveTriggerAction and MouseLeaveTriggerAction are defined as shown in Listing 16.

Listing 16—Silverlight's Trigger usage—code behind.

public class MouseMoveTriggerAction : TriggerAction<Control>
{
    protected override void Invoke(object parameter)
    {
        base.AssociatedObject.Foreground = new SolidColorBrush(Colors.Blue);
    }
}

public class MouseLeaveTriggerAction : TriggerAction<Control>
{
    protected override void Invoke(object parameter)
    {
        base.AssociatedObject.Foreground
   = new SolidColorBrush(SystemColors.ControlTextColor);
    }
}

They both derive from the TriggerAction<Control> class. We've used Control instead of Button because the property we need, Foreground, is defined inside the Control class. In this way, we're able to use our MouseMoveTriggerAction and MouseLeaveTriggerAction in all the controls inside our solution, not just the Buttons. TriggerAction<T> defines an AssociatedObject property, which is the property to which the Trigger applies; in our case, the Button. We've set its Foreground property as needed.

As you can see, even if Triggers in Silverlight are not as powerful as those in WPF, with their help, we're able to separate the XAML code from the code behind. We need only to define the appropriate TriggerAction<T> derived class in a suitable place inside our solution.

Summary

I've introduced you briefly to what WPF and Silverlight are and how they differ from ASP.NET or WinForm programming. In my opinion, not only is XAML a new way to present data to users, but it involves new architectural concepts like those expressed by MVVM. This change influences from the ground up not only the visual part of the application, but the way in which the application has to be developed in its entirety. The transition to these new models isn't always easy; however, after a little experimentation, the real advantages of XAML-based applications become evident. I hope that this article will help to make this transition more enjoyable for you.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020