Export (0) Print
Expand All

Sample: Create, Retrieve, Update and Delete Using the REST Endpoint with Silverlight

[Applies to: Microsoft Dynamics CRM 2011]

This sample code is for Microsoft Dynamics CRM 2011, and can be found in the following location in the SDK download:

SDK/SampleCode/CS/Silverlight/CrmODataSilverlight

If you just want to see how this sample works you can install (import) the CRMODataSilverlightExample_1_0_0_2_managed.zip managed solution included in the download files. If you install this managed solution and want to create the web resources using the names in this topic, your solution publisher customization prefix cannot be “sample” unless you uninstall (delete) the managed solution.

Requirements

For this sample to work, two web resources will be created by using the following names and the content:

sample_/CrmODataSilverlightTestPage.html
An HTML page can be used to view the Silverlight control outside a form. The only purpose of this web resource is to provide the URL of the server when the Microsoft Silverlight control cannot access it itself through the Xrm.Page.context.getServerUrl when the Silverlight web resource is added in an entity form.

sample_/ClientBin/CrmODataSilverlight.xap
The name of this web resource just reflects the relative output location of the .xap file in the Microsoft Visual Studio 2010 Silverlight application (version 4) project.

noteNote
The customization prefix ” sample_” is not used in code. These samples will work using the customization prefix from any publisher. However, the relative path of the simulated Scripts folder must be included in the name of the web resources.

Demonstrates

This sample provides the following:

  • Shows how to perform the most basic data operations using the REST endpoint and Silverlight.

  • Sequentially executes create, retrieve, and update operations on a new account record.

  • Allows you to delete the record created.

  • When prompted to delete the account created, if you decide not to delete the account, a button is displayed that allows for opening the account record that was created and updated.

  • Displays results similar to the following when you preview the sample_/CrmODataSilverlightTestPage.html HTML web resource or add the sample_/ClientBin/CrmODataSilverlight.xap Silverlight web Resource to an entity form:



    Starting Create, Retrieve, Update and Delete Operations
    Created a new account named “New Account Created in Silverlight” with AccountId = “35C82F85-A0A3-4B6A-AA0B-B99BFDD4E357”.
    Retrieved the account named “New Account Created in Silverlight”.
    The account was updated and renamed “Account updated in Silverlight”.
    The account named “Account updated in Silverlight” was deleted.
    Retrieving the first 5 accounts:
    A Store (sample)
    Advanced Components (sample)
    Affordable Equipment (sample)
    Basic Company (sample)
    Best o’ Things (sample)
    Create, Retrieve, Update and Delete Operations Complete.

Preliminary Steps

This Silverlight application uses a service reference named CrmODataServices added using the steps detailed under Generating WCF Data Services Client Data Service Classes. The name of the System.Data.Services.Client context is ” AdventureWorksCycleContext” because the name of the organization was AdventureWorksCycle.

sample_/CrmODataSilverlightTestPage.html

The following sample is the HTML file that is produced when you create a Visual Studio 2010 Silverlight Application (version 4) project named ” CrmODataSilverlight” and select to include a website with it. Only three lines have been modified:

  • The #silverlightControlHost style width is set to 100%.

  • The script reference to the Silverlight.js file is commented out (or removed). This will be provided by Microsoft Dynamics CRM.

  • A script reference to ../ClientGlobalContext.js.aspx was added. This provides access to a context object that is accessed from the code within MainPage.xaml.cs.


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <title>CrmODataSilverlight</title>
 <style type="text/css">
  html, body
  {
   height: 100%;
   overflow: auto;
  }
  body
  {
   padding: 0;
   margin: 0;
  }
  #silverlightControlHost
  {
   height: 100%;
   width: 100%;
   text-align: center;
  }
 </style>
 <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>
 <script type="text/javascript">
  function onSilverlightError(sender, args) {
   var appSource = "";
   if (sender != null && sender != 0) {
    appSource = sender.getHost().Source;
   }

   var errorType = args.ErrorType;
   var iErrorCode = args.ErrorCode;

   if (errorType == "ImageError" || errorType == "MediaError") {
    return;
   }

   var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n";

   errMsg += "Code: " + iErrorCode + "    \n";
   errMsg += "Category: " + errorType + "       \n";
   errMsg += "Message: " + args.ErrorMessage + "     \n";

   if (errorType == "ParserError") {
    errMsg += "File: " + args.xamlFile + "     \n";
    errMsg += "Line: " + args.lineNumber + "     \n";
    errMsg += "Position: " + args.charPosition + "     \n";
   }
   else if (errorType == "RuntimeError") {
    if (args.lineNumber != 0) {
     errMsg += "Line: " + args.lineNumber + "     \n";
     errMsg += "Position: " + args.charPosition + "     \n";
    }
    errMsg += "MethodName: " + args.methodName + "     \n";
   }

   throw new Error(errMsg);
  }
 </script>
</head>
<body>
 <form id="form1" runat="server" style="height: 100%">
 <div id="silverlightControlHost">
  <object type="application/x-silverlight-2" width="100%" height="100%">
   <param name="source" value="ClientBin/CrmODataSilverlight.xap" />
   <param name="onError" value="onSilverlightError" />
   <param name="background" value="white" />
   <param name="minRuntimeVersion" value="4.0.50401.0" />
   <param name="autoUpgrade" value="true" />
   <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration: none">
    <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style: none" />
   </a>
  </object>
  <iframe id="_sl_historyFrame" style="visibility: hidden; height: 0px; width: 0px; border: 0px"></iframe>
 </div>
 </form>
</body>
</html>

sample_/ClientBin/CrmODataSilverlight.xap

This Silverlight file is compiled from files in a Visual Studio 2010 Silverlight application (version 4) project named ‘CrmODataSilverlight’. The only files that were created or modified are as follows:

DeleteConfirmation.xaml
A new XAML page added to provide a dialog when prompting to delete the records created.

DeleteConfirmation.xaml.cs
The Visual C# code-behind file to support DeleteConfirmation.xaml.

MainPage.xaml
The default main page for the Silverlight application.

MainPage.xaml.cs
The Visual C# code-behind file to support MainPage.xaml.

ServerUtility.cs
A static class that provides functions to retrieve the server URL.

DataServiceContextExtensions.cs
Extensions to the AdventureWorksCycleContext as described in Implement Data Service Context Extensions.

DeleteConfirmation.xaml


<controls:ChildWindow x:Class="Microsoft.Crm.Sdk.Samples.DeleteConfirmation"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           Width="400" Height="300" 
           Title="Delete Confirmation">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Button x:Name="CancelButton" Content="No" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
        <Button x:Name="OKButton" Content="Yes" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
        <TextBlock Height="Auto" HorizontalAlignment="Stretch" Margin="5" Name="textBlock1" Text="Do you want to delete the account?" VerticalAlignment="Stretch" />
    </Grid>
</controls:ChildWindow>

DeleteConfirmation.xaml.cs


using System.Windows;
using System.Windows.Controls;
using Microsoft.Crm.Sdk.Samples.CrmODataService;


namespace Microsoft.Crm.Sdk.Samples
{
    public partial class DeleteConfirmation : ChildWindow
    {        
        internal Account accountForDeletion;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="accountForDeletion">The Account to be deleted</param>
        public DeleteConfirmation(Account accountForDeletion)
        {            
            InitializeComponent();
            this.accountForDeletion = accountForDeletion;            
        }

        /// <summary>
        /// Handles the OK Button and sets result to true, representing delete
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

        /// <summary>
        /// Handles the Cancel Button and sets result to false, representing do not delete
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }
    }
}

MainPage.xaml


<UserControl x:Class="Microsoft.Crm.Sdk.Samples.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel x:Name="MessagePanel" VerticalAlignment="Top" />

    </Grid>
</UserControl>

MainPage.xaml.cs


using System;
using System.Collections.ObjectModel;
using System.Data.Services.Client;
using System.Linq;
using System.Threading;
using System.Windows.Controls;
using Microsoft.Crm.Sdk.Samples.CrmODataService;
using System.Net;
using System.Net.Browser;

namespace Microsoft.Crm.Sdk.Samples
{
    public partial class MainPage : UserControl
    {
        private SynchronizationContext _syncContext;
        private AdventureWorksCycleContext _context;
        private String _serverUrl;

        public MainPage()
        {
            InitializeComponent();

            //Keeps a reference to the UI thread
            _syncContext = SynchronizationContext.Current;

            //Get the ServerUrl (ServerUrl is formatted differently OnPremise than OnLine)
            _serverUrl = ServerUtility.GetServerUrl(); 

            if (!String.IsNullOrEmpty(_serverUrl))
            {
                
                //Setup Context
                _context = new AdventureWorksCycleContext(
                    new Uri(String.Format("{0}/xrmservices/2011/organizationdata.svc/", 
                        _serverUrl), UriKind.Absolute));

                //This is important because if the entity has new 
                //attributes added the code will fail.
                _context.IgnoreMissingProperties = true;

                MessagePanel.Children.Add(new TextBlock() {
                    Text = "Starting Create, Retrieve, Update, and Delete Operations."});

                //Begin the Create, Retrieve, Update, and Delete operations. The operations are chained together
                //as each of them is completed.
                BeginCreateAccount();
            }
            else
            {
                //No ServerUrl was found. Display message.
                MessagePanel.Children.Add(new TextBlock()
                {
                    Text =
                        "Unable to access server url. Launch this Silverlight " + 
                        "Web Resource from a CRM Form OR host it in a valid " + 
                        "HTML Web Resource with a " + 
                        "<script src='../ClientGlobalContext.js.aspx' " + 
                        "type='text/javascript'></script>" 
                });
            }
        }

        /// <summary>
        /// Creates an Account record in CRM.
        /// </summary>
        private void BeginCreateAccount()
        {
            Account newAccount = new Account();
            newAccount.Name = "New Account Created in Silverlight";
            _context.AddToAccountSet(newAccount);
            _context.BeginSaveChanges(OnCreateAccountComplete, newAccount);
        }

        /// <summary>
        /// Callback method invoked when Account is done being created.
        /// </summary>
        /// <param name="result"></param>
        private void OnCreateAccountComplete(IAsyncResult result)
        {
            try
            {                
                _context.EndSaveChanges(result);
                Account createdAccount = result.AsyncState as Account;
                MessagePanel.Children.Add(new TextBlock() { 
                    Text = String.Format("Created a new account named \"{0}\"\n\twith AccountId = \"{1}\".",
                        createdAccount.Name, createdAccount.AccountId) 
                });
                
                //Retrieve the Account just created.
                BeginRetrieveAccount(createdAccount.AccountId);
            }
            catch (SystemException se)
            {
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se);
            }
        }

        /// <summary>
        /// Creates a DataServiceQuery to retrieve the Account created in this sample.
        /// </summary>
        /// <param name="Id"></param>
        private void BeginRetrieveAccount(Guid Id)
        {
            try
            {
                DataServiceQuery<Account> query = (DataServiceQuery<Account>)_context
                    .AccountSet.Where<Account>(a => a.AccountId == Id);

                query.BeginExecute(OnRetrieveAccountComplete, query);
            }
            catch (DataServiceQueryException dsqe)
            {
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), dsqe);
            }
        }

        /// <summary>
        /// Extracts the retrieve Account from the query result and Updates the account
        /// </summary>
        /// <param name="result"></param>
        private void OnRetrieveAccountComplete(IAsyncResult result)
        {
            try
            {
                DataServiceQuery<Account> results = 
                    result.AsyncState as DataServiceQuery<Account>;

                Account retrievedAccount = new DataServiceCollection<Account>(results
                    .EndExecute(result)).First<Account>();

                MessagePanel.Children.Add(new TextBlock() { Text = 
                    String.Format("Retrieved the account named \"{0}\".",
                        retrievedAccount.Name) });

                //Update the retrieved Account
                BeginUpdateAccount(retrievedAccount.AccountId);
            }
            catch (SystemException se)
            {
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se);
            }
        }

        /// <summary>
        /// Changes the Account name and saves changes
        /// </summary>
        /// <param name="Id"></param>
        private void BeginUpdateAccount(Guid Id)
        {
            try
            {
                Account updatedAccount = new Account();
                updatedAccount.Name = "Account updated in Silverlight";
                updatedAccount.AccountId = Id;
                _context.AttachTo("AccountSet", updatedAccount);
                _context.UpdateObject(updatedAccount);
                _context.BeginSaveChanges(OnUpdateAccountComplete, updatedAccount);
            }
            catch (SystemException se)
            { 
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se); 
            }
        }

        /// <summary>
        /// Callback method invoked after the Update has occurred. Will prompt user 
        /// to delete the Account.
        /// </summary>
        /// <param name="result"></param>
        private void OnUpdateAccountComplete(IAsyncResult result)
        {
            try
            {
                _context.EndSaveChanges(result);
                Account updatedAccount = result.AsyncState as Account;
                MessagePanel.Children.Add(new TextBlock() { Text = 
                    String.Format("The account was updated and renamed \"{0}\".",
                        updatedAccount.Name) });

                DeleteConfirmation confirm = new DeleteConfirmation(updatedAccount);
                confirm.Closed += new EventHandler(OnDeleteConfirmationClosed) ;
                confirm.Show();
            }
            catch (SystemException se)
            { 
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se); 
            }
        }

        /// <summary>
        /// Handles the DeleteConfirmation.Closed event. If result is true, invokes 
        /// the delete method.
        /// If user chooses no, they are presented the option to open the 
        /// native Account form.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDeleteConfirmationClosed(object sender, EventArgs e)
        {
            //Present a confirmation asking to delete the Account or keep it.
            DeleteConfirmation dlg = (DeleteConfirmation)sender;
            bool? result = dlg.DialogResult;

            //If user chooses Delete, begin deleting the record.
            if (result.HasValue && result.Value)
            {
                BeginDeleteAccount(dlg.accountForDeletion);
            }

            //If user chooses to save, present a Hyperlink to open the native record.
            else
            {
                MessagePanel.Children.Add(new TextBlock() { 
                    Text = "You chose not to delete this account. You can open this\n\t" + 
                    "account record by clicking this button:" });

                MessagePanel.Children.Add(new HyperlinkButton()
                {
                    Content = dlg.accountForDeletion.Name,
                    TargetName = "_blank",
                    Width =  200,
                    VerticalAlignment = System.Windows.VerticalAlignment.Center,
                    HorizontalAlignment= System.Windows.HorizontalAlignment.Left,
                    
                    //Create a link to open account type.
                    NavigateUri = new Uri(_serverUrl + 
                        String.Format("/main.aspx?etc=1&id={0}&pagetype=entityrecord", 
                            dlg.accountForDeletion.AccountId))
                });

                //Retrieve multiple Accounts
                BeginRetrieveAccounts();
            }
        }
  
        /// <summary>
        /// Marks the account state ready for Delete and
        /// </summary>
        /// <param name="accountToDelete"></param>
        private void BeginDeleteAccount(Account accountToDelete)
        {
            try
            { 
                _context.DeleteObject(accountToDelete);
                _context.BeginSaveChanges(OnDeleteAccountComplete, accountToDelete);
            }
            catch (SystemException se)
            { 
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se); 
            }
        }

        /// <summary>
        /// Ends the Delete message and tries to retrieve multiple accounts
        /// </summary>
        /// <param name="result"></param>
        private void OnDeleteAccountComplete(IAsyncResult result)
        {
            try
            {
                Account deletedAccount = result.AsyncState as Account;
                _context.EndSaveChanges(result);
                
                MessagePanel.Children.Add(new TextBlock() { Text = 
                    String.Format("The Account named \"{0}\" was deleted.",
                        deletedAccount.Name) });

                //Retrieve multiple Accounts
                BeginRetrieveAccounts();
            }
            catch (SystemException se)
            { 
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se); 
            }            
        }

        /// <summary>
        /// Retrieves the first 5 accounts found.
        /// </summary>
        private void BeginRetrieveAccounts()
        {
            //Retrieve 5 accounts
            int numberToRetrieve = 5;
            DataServiceQuery<Account> accounts = (DataServiceQuery<Account>)this._context
                .AccountSet.Take<Account>(numberToRetrieve);

            MessagePanel.Children.Add(new TextBlock() { Text = 
                String.Format("Retrieving the first {0} accounts:",
                    numberToRetrieve) });

            try
            {                 
                accounts.BeginExecute(OnRetrieveAccountsComplete, accounts); 
            }
            catch (DataServiceQueryException dsqe)
            {
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), dsqe);
            }
        }
        
        /// <summary>
        /// Displays the names from any Accounts retrieved.
        /// </summary>
        /// <param name="result"></param>
        private void OnRetrieveAccountsComplete(IAsyncResult result)
        {
            //Retrieve the query that was 
            DataServiceQuery<Account> results = result.AsyncState as DataServiceQuery<Account>;

            try
            {
                //Create a collection of Accounts and set it equal to the query result
                ObservableCollection<Account> _accounts = 
                    new DataServiceCollection<Account>(results.EndExecute(result));
                
                //For each Account found, display the Account Name
                foreach (Account account in _accounts)
                {
                    MessagePanel.Children.Add(new TextBlock() { Text = account.Name });
                }

                MessagePanel.Children.Add(new TextBlock()
                {
                    Text = "Create, Retrieve, Update, and Delete Operations Complete."
                });
            }
            catch (SystemException se)
            {
                _syncContext.Send(new SendOrPostCallback(showErrorDetails), se);
            }
        }

        /// <summary>
        /// Will display exception details if an exception is caught.
        /// </summary>
        /// <param name="ex">An System.Exception object</param>
        private void showErrorDetails(object ex)
        {
            //Assure the control is visible
            MessagePanel.Visibility = System.Windows.Visibility.Visible;

            Exception exception = (Exception)ex;
            String type = exception.GetType().ToString();

            MessagePanel.Children.Add(new TextBlock() { Text = 
                String.Format("{0} Message: {1}", type, exception.Message) });

            MessagePanel.Children.Add(new TextBlock() { Text = 
                String.Format("Stack: {0}", exception.StackTrace) });

            if (exception.InnerException != null)
            {
                String exceptType = exception.InnerException.GetType().ToString();
                MessagePanel.Children.Add(new TextBlock() { Text = 
                    String.Format("InnerException: {0} : {1}", exceptType, 
                        exception.InnerException.Message) });
            }
        }
    }
}

ServerUtility.cs


using System;
using System.Windows.Browser;

namespace Microsoft.Crm.Sdk.Samples
{
    public static class ServerUtility
    {
        /// <summary>
        /// Returns the ServerUrl from Microsoft Dynamics CRM
        /// </summary>
        /// <returns>String representing the ServerUrl or String.Empty if not found.</returns>
        public static String GetServerUrl()
        {
            String serverUrl = String.Empty;

            //Try to get the ServerUrl from the Xrm.Page object
            serverUrl = GetServerUrlFromContext();            

            return serverUrl;
        }

        /// <summary>
        /// Attempts to retrieve the ServerUrl from the Xrm.Page object
        /// </summary>
        /// <returns></returns>
        private static String GetServerUrlFromContext()
        {
            try
            {
                // If the Silverlight is in a form, this will get the server url
                ScriptObject xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
                ScriptObject page = (ScriptObject)xrm.GetProperty("Page");
                ScriptObject pageContext = (ScriptObject)page.GetProperty("context");

                String serverUrl = (String)pageContext.Invoke("getServerUrl");

                //The trailing forward slash character from CRM Online needs to be removed.
                if (serverUrl.EndsWith("/"))
                {
                    serverUrl = serverUrl.Substring(0, serverUrl.Length - 1);
                }

                return serverUrl;
            }
            catch
            {
                return String.Empty;
            }
        }
    }
}

DataServiceContextExtensions.cs


using System;
using System.Linq;
using System.Data.Services.Client;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml.Linq;

namespace Microsoft.Crm.Sdk.Samples.CrmODataService
{
 partial class AdventureWorksCycleContext
	{
		#region Methods
		partial void OnContextCreated()
		{
			this.ReadingEntity += this.OnReadingEntity;
			this.WritingEntity += this.OnWritingEntity;
		}
		#endregion

		#region Event Handlers
		private void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e)
		{
			ODataEntity entity = e.Entity as ODataEntity;
			if (null == entity)
			{
				return;
			}

			entity.ClearChangedProperties();
		}

		private void OnWritingEntity(object sender, ReadingWritingEntityEventArgs e)
		{
			ODataEntity entity = e.Entity as ODataEntity;
			if (null == entity)
			{
				return;
			}

			entity.RemoveUnchangedProperties(e.Data);
   entity.ClearChangedProperties();
		}
		#endregion
	}

	public abstract class ODataEntity
	{
		private readonly Collection<string> ChangedProperties = new Collection<string>();

		public ODataEntity()
		{
			EventInfo info = this.GetType().GetEvent("PropertyChanged");
			if (null != info)
			{
				PropertyChangedEventHandler method = new PropertyChangedEventHandler(this.OnEntityPropertyChanged);

				//Ensure that the method is not attached and reattach it
				info.RemoveEventHandler(this, method);
				info.AddEventHandler(this, method);
			}
		}

		#region Methods
		public void ClearChangedProperties()
		{
			this.ChangedProperties.Clear();
		}

		internal void RemoveUnchangedProperties(XElement element)
		{
			const string AtomNamespace = "http://www.w3.org/2005/Atom";
			const string DataServicesNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices";
			const string DataServicesMetadataNamespace = DataServicesNamespace + "/metadata";

			if (null == element)
			{
				throw new ArgumentNullException("element");
			}

			List<XElement> properties = (from c in element.Elements(XName.Get("content", AtomNamespace)
												   ).Elements(XName.Get("properties", DataServicesMetadataNamespace)).Elements()
										 select c).ToList();

			foreach (XElement property in properties)
			{
				if (!this.ChangedProperties.Contains(property.Name.LocalName))
				{
					property.Remove();
				}
			}
		}

		private void OnEntityPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (!this.ChangedProperties.Contains(e.PropertyName))
			{
				this.ChangedProperties.Add(e.PropertyName);
			}
		}
		#endregion
	}
}

See Also

Microsoft Dynamics CRM 2011
Send comments about this topic to Microsoft.
© 2013 Microsoft Corporation. All rights reserved.
Was this page helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

Show:
© 2014 Microsoft