The ProductList
control is yet another specialized list control that displays a checklist of products. It allows the user to select products that a lead, opportunity, or customer might be interested in by ticking this checklist.
This control will first retrieve the latest list of products from the Products
table in the database via the GetProductList()
method you've created in Chapter 2. When the user attempts to save the account record, the product codes of the selected items in the ProductList
control will be saved in XML format using Microsoft's XML libraries. This XML object is then serialized into a single string, which is eventually committed to the BaseAccount.InterestedProds
field.
A similar process also happens in the opposite direction. When an account record is loaded, the XML object is rebuilt from the BaseAccount.InterestedProds
field. A code routine runs through this XML object to retrieve the selected product codes and correspondingly places a tick next to each item in the checklist.
Let's begin to build this control. Add a new class to your SalesForceApp
project and make it inherit the ListView
class. The SetupListView()
method sets up the columns and settings for this list.
using System;
using System.Windows.Forms;
using System.Xml;
using System.IO;
namespace CRMLive
{
public class ProductList : System.Windows.Forms.ListView
{
private string _Datasource;
internal System.Windows.Forms.ColumnHeader
ColumnHeader1;
internal System.Windows.Forms.ColumnHeader
ColumnHeader2;
internal System.Windows.Forms.ColumnHeader
ColumnHeader3;
private XmlDocument _xmlDoc;
private XmlElement _xmlRoot;
private void SetupListView()
{
base.CheckBoxes = true;
ColumnHeader1 = new ColumnHeader();
ColumnHeader2 = new ColumnHeader();
ColumnHeader3 = new ColumnHeader();
ColumnHeader1.Text = "Code";
ColumnHeader1.Width = 59;
ColumnHeader2.Text = "Product Name";
ColumnHeader2.Width = 100;
ColumnHeader3.Text = "Product Price";
ColumnHeader3.Width = 50;
base.Columns.Add(this.ColumnHeader1);
base.Columns.Add(this.ColumnHeader2);
base.Columns.Add(this.ColumnHeader3);
base.Font = new System.Drawing.Font("Tahoma", 8.0F,
System.Drawing.FontStyle.Regular);
base.FullRowSelect = true;
base.View = System.Windows.Forms.View.Details;
}
private void MarkProduct(string ProductCode)
{
int _counter;
for (_counter = 0; _counter <= base.Items.Count - 1;
_counter++)
{
if (String.Compare(base.Items[_counter].Text,
ProductCode,true) == 0)
{
base.Items[_counter].Checked = true;
return;
}
}
}
public ProductList()
{
SetupListView();
LoadProducts();
}
}
}
The LoadProducts()
method will loop through the retrieved ProductCollection
and generate the corresponding list view items.
private void LoadProducts() { ProductCollection _products; int _counter; ListViewItem _listViewItem; Product _product; try { base.Items.Clear(); _products = GlobalArea.Application.GetProductList(); for (_counter = 0; _counter <= _products.Count 1; _counter++) { _product = _products[_counter]; _listViewItem = new ListViewItem(_product.ProductCode); _listViewItem.SubItems.Add (_product.ProductName); _listViewItem.SubItems.Add (_product.ProductPrice.ToString()); base.Items.Add(_listViewItem); } } catch (Exception) { } }
At this point we have a list view control that can display a checklist of all products stored in the database, but without the capability to save or load any user selection yet.
The .NET Compact Framework provides a set of classes that allow you to manipulate XML. These classes are contained in the System.Xml
namespace. The XMLDocument
class is the first class you need to get familiar with. It provides the methods to create new XML elements and attributes.
In the Get()
method of the Datasource
property shown in the following snippet, we loop through all ListView items and for those items that are checked, create a new XML element to store the corresponding Product Code. For example, if the user ticked two products from the checklist, you will end up with the following XML:
<Root> <Product ProductCode='C01' /> <Product ProductCode='C02' /> </Root>
The code snippet to achieve the above is shown as follows:
public string Datasource { get { XmlElement _xmlProduct; string _productCode; XmlTextWriter _xmlWriter; StringWriter _stringWriter; int _counter; //Loop through the ListView items and create the //corresponding XML object _xmlDoc = new XmlDocument(); _xmlRoot = _xmlDoc.CreateElement("Root"); _xmlDoc.AppendChild(_xmlRoot); for (_counter = 0; _counter <= base.Items.Count - 1; _counter++) { if (base.Items[_counter].Checked == true) { _productCode = base.Items[_counter].Text; _xmlProduct = _xmlDoc.CreateElement("Product"); _xmlProduct.SetAttribute("ProductCode", _productCode); _xmlRoot.AppendChild(_xmlProduct); } } //Serialize the XML into a single string _stringWriter = new StringWriter(); _xmlWriter = new XmlTextWriter(_stringWriter); _xmlDoc.WriteTo(_xmlWriter); _xmlWriter.Close(); _xmlWriter = null; _xmlDoc = null; return _stringWriter.ToString(); } set { int _counter; XmlElement _xmlProduct; string _productCode; _Datasource = value; if (_Datasource.Length > 0) { //Rebuilds the XML object from a single string _xmlDoc = new XmlDocument(); _xmlDoc.LoadXml(_Datasource); //Loops through each XML element and retrieves the //stored product codes. The MarkProduct() //method is called to place a tick next to each //corresponding ListView item _xmlRoot = (XmlElement) (_xmlDoc.ChildNodes.Item(0)); for (_counter = 0; _counter <= _xmlRoot.ChildNodes.Count - 1; _counter++) { _xmlProduct = (XmlElement) (_xmlRoot.ChildNodes.Item(_counter)); _productCode = _xmlProduct.GetAttribute("ProductCode"); MarkProduct(_productCode); } _xmlDoc = null; } } }
Create the Interest tab in the AccountViewer
form and drag the ProductList
control you've created into the tab frame. As the ProductList
control is capable of retrieving the list of Products from the database on its own, the only data you need to bind to this control would be the user selection XML, contained in the BaseAccount.InterestedProds
field. You can do this in the SetupBindings()
method of the AccountViewer
form:
public void SetupBindings()
{
if (_account != null)
{
AccountBindingSource.DataSource = typeof(BaseAccount);
AccountBindingSource.Add(_account);
.
.
.
plProducts.DataBindings.Add(new Binding("DataSource",
AccountBindingSource, "InterestedProds", true));
}
}
Before you can test this control, you will need to have a few sample products in your database. Open the Query Analyzer or MSql tool (depending on the database you are using), and run the following SQL:
INSERT INTO Products(ProductCode, ProductName, ProductPrice) VALUES('C1', 'The Chair', 2500) INSERT INTO Products(ProductCode, ProductName, ProductPrice) VALUES('C2', 'Annual Subscription', 500) INSERT INTO Products(ProductCode, ProductName, ProductPrice) VALUES('C3', '6-month subscription', 300)
For the Oracle Lite database, don't forget to explicitly specify the sequence number source for the ProductID
column.
Run the sales force application again. Navigate to the Interest tab. You will find the list of products showing in the Datagrid. Tick any number of items you wish and click Save to save the account details together with your selection.
If you browse the database using Query Analyzer or MSql, you will find that your selection has been saved as XML in the InterestedProds
column of the Accounts
table.
52.14.8.34