How to create a single list view
There are two options for you to begin.
Create the view from scratch
The only thing that your view needs to do to be a legal Site Manager view is to inherit from the base Site Manager view:
public partial class SingleListView : LSOne.ViewCore.ViewBase
You will then have to overwrite key methods from the base class to get your functionality ready. To get an idea of which functions to overload, see the functions overview below.
Copy SingleListView from the Hello World plugin
You can copy almost any view from the Site Manager and customize it based on your needs. To make this process simpler we have created view templates with minimal functionality included. You can find a template view for a single list view in the Hello World plugin from the Site Manager part of the development package. The view is called SingleListView and you can copy it into your plugin. The view contains a shell for the basic functionality of a single list view.
Functions overview
Base functions
This is a list of functions that are most commonly overwritten to add logic to your view:
Base functions |
Description |
void LoadData( |
Here we load data into our list view. This involves fetching the list of data objects and populating the list view with it. The isRevert variable is false unless the user pressed the Revert button above the Context bar. That function is supposed to revert to the last saved state of the view (basically reverting all changes that have not yet been saved). |
RecordIdentifier ID |
Returns the ID of the view and is used to determine if the view is already visible and does not need to be reloaded. Usually you return the ID of the object that you are working with, but since you have a list view you return RecordIdentifier.Empty |
string LogicalContextName |
Returns the string that should appear directly above the Context bar. |
void GetAuditDescriptors( List<AuditDescriptor> contexts) |
Connects the view with an audit view. See chapter Auditing for more details. |
void OnDataChanged(..) |
This is the opposite function of NotifyDataChanged(..) function that we covered in chapter How to create a simple view . This is the listener function and when another view or dialog wants to notify all open views about changes then this function is called. This function is mainly used to reload the list of objects to make sure we are showing the latest version of the data. |
List view operations
This is a list of common functions that are connected to the list view:
List view functions |
Description |
void listView_SelectionChanged(..) |
This function is called when the user changes the selected index of the list view. Here you need to check if the user clicked on a data object row or if he clicked outside the data rows. If he did not click on a data object row you need to disable the edit and delete buttons. |
void listView_RowDoubleClick(..) |
This function is called when the user double clicks on a row in the list view. Here you need to make sure that the user clicked on a data object row. If he did you should open the edit view or dialog. |
void listView_HeaderClicked(..) |
This function is called when the user clicks on a column in the list view. This is usually used to order the results of the list view depending on the clicked column. Note that to keep the examples simple this function is not used in the Hello World SingleListView. |
void ContextMenuStrip_Opening(..) |
This function is called when the user right-clicks on the list view. This function is usually linked to the list view in the constructor. In this function you can add different operations that appear to the user in a drop-down list. |
Buttons operations
This is a list of the three functions behind the context buttons that are usually located below the list view. Note that it is customary in the Site Manager to disable buttons that you cannot press. This means that the user should not be able to open an add dialog if they do not have permission to add the object.
Context buttons functions |
Description |
void btns_AddButtonClicked(..) |
This operation is called when the user presses the green plus button below the list view. This usually triggers a dialog showing either all the fields that can be edited or just the mandatory fields. If only mandatory fields are shown then the user is redirected to a view for the data object where they can edit the optional parameters of the object. |
void btns_EditButtonClicked(..) |
This operation is called when the user presses the yellow pencil button below the list view. This should either trigger a dialog where the data object can be edited (if it has a limited amount of information) or another view where the data object can be edited. |
void btns_RemoveButtonClicked(..) |
This operation is called when the user presses the red minus button below the list view. This usually triggers a question if the user really wants to delete the selected object (this is not a requirement). If the user presses Yes then the data object is deleted through the data layer. |
Sample code walkthrough
public SingleListView(RecordIdentifier selectedId)
: this()
{
this.selectedId = selectedId;
}
public SingleListView()
{
InitializeComponent();
Attributes = ViewAttributes.Audit |
ViewAttributes.Close |
ViewAttributes.ContextBar |
ViewAttributes.Help;
HeaderText = "Single list view header text";
btnsEditAddRemove.AddButtonEnabled = PluginEntry.DataModel.HasPermission(Permission.SingleListViewPermission);
lvDataObjects.ContextMenuStrip = new ContextMenuStrip();
lvDataObjects.ContextMenuStrip.Opening += ContextMenuStrip_Opening;
}
The list view has two constructors. An empty one where no row should have focus or one with an ID parameter so that the row with the selected ID can have focus when the view opens.
Also notice that the selectedId constructor calls the empty constructor through the this() call.
So in both cases the Attributes of the view are set. These attributes decide which operations the view supports. If you, for example, choose not to include a ViewAttributes.Close parameter in attributes then the user will not get a Close button on the top of the Context bar.
The next line enables or disables the Add button based on if the user has the permission SingleListViewPermission. To learn more about permissions see chapter Permissions.
The last two lines are there to make right-clicking the list view open the ContextMenuStrip_Opening function.
private void LoadItems()
{
RecordIdentifier oldSelectedID = selectedID;
lvDataObjects.ClearRows();
List<DataObject> dataObjects = Providers.DataObjectData.GetList(PluginEntry.DataModel);
foreach (DataObject obj in dataObjects)
{
Row row = new Row();
row.AddText(obj.Text);
row.AddText(obj.ExtraInfo);
row.Tag = obj.ID;
lvDataObjects.AddRow(row);
if (oldSelectedID == obj.ID)
{
lvDataObjects.Selection.Set(lvDataObjects.RowCount - 1);
}
}
lvDataObjects.AutoSizeColumns();
lvDataObjects_SelectionChanged(this, EventArgs.Empty);
}
Here we have our data load functions. As you can see the function doing all the work is the LoadItems() function. We start by clearing existing items from the list view to make sure that we are loading into an empty list view. We then use our data layer class to fetch a list of data objects.
Then we loop through each of the objects and create rows in which we add each cell, then add the rows to the list view. Note that the order in which you add the cells is the same order as the list view columns. So here, for example, we are adding the Text property of the object first and then the ExtraInfo property. This means that the Text property goes into the first column and the ExtraInfo property goes into the second column.
Before the item is added to the list view we assign it a Tag. The Tag property is an object where we can store anything. We choose to store the ID of the object in it, because when we edit a DataObject we need to access the object ID of the row selected, which we get from the Tag of the row.
After we add the item to the list we check to see if the object we are loading into the list view has the same ID as the ID we got from the constructor (if we have an ID from the constructor) or a previously selected ID. If it does, we set the item to be selected.
The last two lines, lvDataObjects_SelectionChanged(..); makes sure that the edit and remove buttons are appropriately enabled. lvDataObjects.AutoSizeColumns(); automatically resizes the columns so that there is just enough space in each column considering the data in it.
public override void OnDataChanged(DataEntityChangeType changeAction,
string objectName,
RecordIdentifier changeIdentifier,
object param)
{
if (objectName == "dataObject")
{
LoadItems();
}
}
The OnDataChanged(..) function is used to respond to data changes in other views. It has a lot of parameters, and these are the same parameters as the function NotifyDataChanged(..), which is the function that always calls this function. If another view or dialog calls NotifyDataChanged(..) with the parameter objectName = dataObject then we want to reload our objects list.
This would usually happen from the view that edits a single customer. If that view, for example, changes the name of the customer then we want to know about it so that we can reload our list and show the new name of that customer.
private void lvDataObjects_SelectionChanged(object sender, EventArgs e)
{
btnsEditAddRemove.EditButtonEnabled =
btnsEditAddRemove.RemoveButtonEnabled = lvDataObjects.SelectedItems.Count > 0 &&
PluginEntry.DataModel.HasPermission(Permissions.ManageSingleList);
}
private void lvDataObjects_RowDoubleClick(object sender, EventArgs e)
{
if (btnsEditAddRemove.EditButtonEnabled)
{
btnsEditAddRemove_EditButtonClicked(this, EventArgs.Empty);
}
}
void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
{
ContextMenuStrip menu = lvDataObjects.ContextMenuStrip;
menu.Items.Clear();
var item = new ExtendedMenuItem(
Properties.Resources.Edit,
100,
btnsEditAddRemove_EditButtonClicked);
item.Image = btnsEditAddRemove.EditButtonImage;
item.Enabled = btnsEditAddRemove.EditButtonEnabled;
item.Default = true; // The default item has a bold font
menu.Items.Add(item);
item = new ExtendedMenuItem(
Properties.Resources.Add,
200,
new EventHandler(btnsEditAddRemove_AddButtonClicked));
item.Enabled = btnsEditAddRemove.AddButtonEnabled;
item.Image = btnsEditAddRemove.AddButtonImage;
menu.Items.Add(item);
item = new ExtendedMenuItem(
Properties.Resources.Delete,
300,
new EventHandler(btnsEditAddRemove_RemoveButtonClicked));
item.Image = btnsEditAddRemove.RemoveButtonImage;
item.Enabled = btnsEditAddRemove.RemoveButtonEnabled;
menu.Items.Add(item);
e.Cancel = (menu.Items.Count == 0);
}
Here we have three functions:
- lvDataObjects_SelectionChanged makes sure that there are some lines selected in the list view. If there are and the use has a specific permission, we enable the Edit and Remove buttons.
- lvDataObjects_RowDoubleClick first checks to see if the Edit button is enabled. If it is then we call the Edit button operation.
- ContextMenuStrip_Opening adds items to the right-click-drop-down list view.
Note that we are using most of the properties from our Add, Edit and Remove buttons. We are using the functions behind the buttons, enabling/disabling based on the enabled status of each button and using the images from the buttons. Note that one of the items we are adding to the list has a default flag. This means that this item is formatted in bold on the list.
The last thing to note about this function is the fact that this function is almost always the same. Most likely you will not have to change this function at all and the only thing you have to do is add the strings to your plugin that are used when displaying the drop-down list.
private void btnsEditAddRemove_EditButtonClicked(object sender, EventArgs e)
{
RecordIdentifier selectedId = (RecordIdentifier)lvDataObjects.Selection[0].Tag;
PluginOperations.ShowDataObjectView(selectedId);
}
private void btnsEditAddRemove_AddButtonClicked(object sender, EventArgs e)
{
var dlg = new Dialogs.DataObjectDialog();
if (dlg.ShowDialog() == DialogResult.OK)
{
LoadItems();
}
}
private void btnsEditAddRemove_RemoveButtonClicked(object sender, EventArgs e)
{
if (QuestionDialog.Show(
Properties.Resources.DeleteDataObjectQuestion,
Properties.Resources.DeleteDataObject) == DialogResult.Yes)
{
RecordIdentifier selectedId = (RecordIdentifier)lvDataObjects.Selection[0].Tag;
PluginProviders.DataObjectData.Delete(PluginEntry.DataModel, selectedId);
LoadItems();
}
}
Here we have three functions:
- btnsEditAddRemove_AddButtonClicked is the function behind the green plus button. This function simply opens the DataObjectDialog and if the user pressed the OK button in that dialog we reload our list view (since OK means that the user was adding an object).
- btnsEditAddRemove_EditButtonClicked is the function behind the yellow pen button. This function does two things. First it fetches the ID of the selected line of the list view (remember that we put the ID of the object in the Tag object of the list view line). Then it calls a method which shows an object view for a given ID.
- btnsEditAddRemove_RemoveButtonClicked is the function behind the red minus button. First this function pops up a question dialog asking if the user really wants to delete the object (this is not a requirement). If the user selects Yes then we fetch the ID of the selected object (as when editing) and use the data layer to delete the selected object.
Next you learn about the double list view: How to create a double list view