Wix: How can I set, at runtime, the text to be displayed in VerifyReadyDlg? - wix

After the user goes through the Setup Wizard, and makes a few choices, the usual thing is to display the VerifyReadyDlg to say "Are you ready to install?"
The built-in VerifyReadyDlg is static. It does not present a summary of the choices he made previously. I'd like to modify it so that it does.
How can I do that?
Example
"Static" text:
Intelligent text:
I don't believe I can modify the Control table in the MSI, because mods during the installation process are not allowed. I found MsiViewModifyInsertTemporary, but I don't think that will work either. The relevant row in the Control table is already present, and it contains static data. I want to modify the data, just before VerifyReadyDlg is displayed.

You may not be able to modify existing rows in the MSI tables, but you can insert new "temporary" rows.
So, in a custom action, at runtime, insert one or more temporary rows into the Control table. In Javascript, it looks like this:
var controlView = Session.Database.OpenView("SELECT * FROM Control");
controlView.Execute();
var record = Session.Installer.CreateRecord(12);
record.StringData(1) = "VerifyReadyDlg"; // Dialog_ - the dialog to mod
record.StringData(2) = "CustomVerifyText1"; // Control - any unique name will do
record.StringData(3) = "Text"; // Type
record.IntegerData(4) = 25; // X
record.IntegerData(5) = 70; // Y
record.IntegerData(6) = 320; // Width
record.IntegerData(7) = 65; // Height
record.IntegerData(8) = 2; // Attributes
record.StringData(9) = ""; // Property
record.StringData(10) = text1; // Text - the text to be displayed
record.StringData(11) = ""; // Control_Next
record.StringData(12) = ""; // Help
controlView.Modify(MsiViewModify.InsertTemporary, record);
controlView.Close();
You probably want that custom text to be displayed only upon INSTALL. In that case, add a condition, in the same way:
var controlCondView = Session.Database.OpenView("SELECT * FROM ControlCondition");
controlCondView.Execute();
record = Session.Installer.CreateRecord(4);
record.StringData(1) = "VerifyReadyDlg"; // Dialog_
record.StringData(2) = "CustomVerifyText1"; // Control_ - same name as above
record.StringData(3) = "Show"; // Action
record.StringData(4) = "NOT Installed"; // Condition
controlCondView.Modify(MsiViewModify.InsertTemporary, record);
controlCondView.Close();
The Msi constants are defined like this:
// http://msdn.microsoft.com/en-us/library/aa372516(VS.85).aspx
var MsiViewModify =
{
Refresh : 0,
Insert : 1,
Update : 2,
Assign : 3,
Replace : 4,
Merge : 5,
Delete : 6,
InsertTemporary : 7, // cannot permanently modify the MSI during install
Validate : 8,
ValidateNew : 9,
ValidateField : 10,
ValidateDelete : 11
};
A couple notes:
The InstallText in the Control table is normally displayed. It can be customized with a .wxl file, inserting something like this:
<String Id="VerifyReadyDlgInstallText">Whatever.</String>
This results in a row in the Control table. But you cannot remove rows from the table at runtime.
If you choose the X,Y and Height,Width for your new custom text to be the same as for the static InstallText, the InstallText will be obscured.
It may seem counter-intuitive to use "NOT Installed" as the condition - but remember, this is the state of the world prior to running the Setup Wizard. If the MSI is Installed prior to running the Wizard, then you're probably not installing it, which means you don't need to display the choices being made in the wizard.
Of course you can add multiple controls this way. You could add multiple Text controls, or...You can add lines, buttons, checkboxes, whatever. For each one, you'll have to set the control type and geometry appropriately. Use Orca to examine the Control table to figure out how.
This approach works for any Dialog. You only have to be sure to run the custom action to insert the temp rows into the Control table, at some point in the InstallUISequence, before the Dialog is rendered.

Related

Remove "MIME type" column from Filent Content List

I am Using a Script Adapter by passing payload to get contend for a Content List from "Search with values" event
When Contend get loaded to content list , i have a custom view to preview them. But if i clicked on MIME type column , It opens a separate view with the mapped viewer
So I need to remove this column or make it un-clickable
1) I am passing search values to content list's "Search with values" event , from where can i handle Content List's contend loading ,any Dojo Event i can use ?
2) With Script Adapter can i do this without going for a "response filter"
Edit :
As Nicely explained by "Ivo Jonker" (in his answer - "or try to specifically locate the widgets on your page" and with his example code)
responsed = page.ContentList8.ecmContentList.getResultSet();
var cols = responsed.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
page.ContentList78.ecmContentList.setResultSet(responsed);
I simply remove this row. Thanks Again and lovely blog , hope you keep posting more great articles.
The values passed through the Search With Values event will eventually be handled by the icm.pgwidget.contentlist.dijit.DocumentSearchHandler
that in turn creates a SearchTemplate to execute the search (ecm.model.SearchTemplate.prototype.search). One option would be to aspect/before/around the DocumentSearchHandler#query to manipulat the searchresults and by that way to remove the column.
The wiring however does not provide any handles to achieve this for a specific query-resultset combination leaving you to either fix this on a global scale (icm.pgwidget.contentlist.dijit.DocumentSearchHandler.prototype#query), or try to specifically locate the widgets on your page.
Personally, taking into account #2, i'd go for the responsefilter-option if you feel the global solution wouldn't be a problem, or alternatively i'd personally prefer to create a simple ICM widget that instantiates/implements a "plain" ecm.widget.listView.ContentList and exposes a wire to set the ecm.model.Resultset.
You'd then be able to create your own Searchquery in a scriptadapter, remove the column, and pass the resultset.
The script adapter could be something like:
var scriptadapter=this;
var queryParams={};
queryParams.query = "SELECT * FROM Document where id in /*your list*/";
queryParams.retrieveAllVersions = false;
queryParams.retrieveLatestVersion = true;
queryParams.repository = ecm.model.desktop.repositories[0];
queryParams.resultsDisplay = {
"sortBy": "{NAME}",
"sortAsc": true,
"columns": ["{NAME}"],
"honorNameProperty": true};
var searchQuery = new ecm.model.SearchQuery(queryParams);
searchQuery.search(function(response/*ecm.model.Resultset*/){
//remove the mimeTypeIcon
var cols = response.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
//emit the resultset to your new contentlist, be sure to block the regular synchrounous output of the scriptadapter
scriptadapter.onPublishEvent("icm.SendEventPayload",response);
//The contentlist wire would simply do contentlist.setResultSet(response);
});

virtual ClistCtrl with checkboxes on displayed report list style

I have an MFC SDI application to display a list of data read from a csv file. So I set up its view to be inherited from CListView and make it a virtual list control. That means I have to use LVS_OWNERDATA as one of its CListCtrl style attributes. Yet I now run into a problem when I have to include Checkboxes in each row of the displayed list. As you might know, LVS_EX_CHECKBOXES can't be used with LVS_OWNERDATA, I therefore create a bitmap file to contain 2 small images of checkbox (selected and de-selected) and toggle them every time the user clicks on the loaded image/icon. I am handling this in OnNMClick method. And I have two problems I would like to ask for your help to solve.
(1) I don't know how to update the virtual list (which is commonly handled in OnLvnGetdispinfo method) so I try this in OnNMClick and find that the check and unchecked images aren't toggled.
void CMFCSDITest::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
LVHITTESTINFO hitinfo;
hitinfo.pt = pNMItemActivate->ptAction;
int nItem = pListCtrl->HitTest(&hitinfo);
if (hitinfo.flags != LVHT_ONITEMICON)
return;
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
LV_ITEM* pItem = &(pDispInfo)->item;
if (pItem->iImage == 0)
pItem->iImage = 1;
else
pItem->iImage = 0;
pListCtrl->SetItem(pItem);
pListCtrl->UpdateWindow(); //this is wrong as nothing seems updated after all.
}
Given that the created imagelist is inserted into the pListCtrl already (in OnInitialUpdate method) and I set the output image index value in OnLvnGetdispinfo method.
(2) Instead of handling OnNMClick, I read somewhere people's advice that OnLvnItemchanged method could also be used. However in LPNMLISTVIEW struct, there is uNewState and uOldState variable members for which I don't know how to set up my tiny checked and unchecked icons as status images. Because I might have to do this
if (pNMLV->uChanged & LVIF_STATE)
{
switch (pNMLV->uNewState & LVIS_STATEIMAGEMASK)
{
case image1://do
case image2://do
}
}

Gridcontrol edit/update mandatory fields different colour

I'm just wondering how can I change background colour of mandatory fields while adding new row.
So for example name and surname would be red (mandatory) and phone would be default white.
Thank you
Patryk
The best way to do this is through the grid's designer -- in most cases you don't need to write any code to accomplish this.
If you go to the Grid View designer, select the menu item "Appearance" and "Format Rules:"
From here, you can add a format condition by clicking the plus icon:
Under "Column," pick the column you want the format condition to apply to.
Under "Rule," pick an appropriate rule -- based on what you described, you probably want "Format Based on a Value," FormatConditionRuleValue.
On the "Rule" tab of this same dialog, you can set your "Value1" and "Condition" properties accordingly, for example Value1 = 15, Condition = "equals."
The "Appearance" property will let you determine how to format the cell based on these conditions.
The beauty of this approach is it's all designer-based code, and it's very easy to customize. The logic behind the formatting is also very transparent. The format conditions have been expanded to let you evaluate expressions as well, meaning you can create your own formulas using other column values and functions.
If all else fails, you can use the RowCellStyle event, but my first attempt would always to be to use the designer tools.
You can use an event gvView_CustomDrawCell and set background color only if the line is in state that you need (Added, Detached ...)
private void gvView_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
{
if (e.Column != null && (e.Column.Name == bgcName.Name || e.Column.Name == bgcSureName.Name))
{
DataRow focusedRow = gvView.GetDataRow(e.RowHandle);
if (focusedRow != null)
{
if (focusedRow.RowState == DataRowState.Added)
{
e.Appearance.BackColor = Color.FromArgb(80, 10, 30, 200);
}
}
}
}
asd

Modifying column header names in Master-Detail grid in Devexpress

I have a Master-Detail set up with 2 grids. On the master grid, I have the ShowOnlyPredefinedDetails option set to false.
This means that I see a little + sign that allows me to expand the details of the detail grid (in the master grid). I would like to rename
some columns in that section as well as hide certain columns. I'm using VB.NET How do I go about this. See image.
You can accomplish this by using the grid control ViewRegistered event, from there you can modify the columns in that grid view that have columns within them that you want to modify, rename, or remove. Here is an example, I hope that it helps:
private void myGridControl_ViewRegistered(object sender, DevExpress.XtraGrid.ViewOperationEventArgs e)
{
if (e != null)
{
if (e.View != null)
{
//Inside of this statement you can adjust, add, and modify all of the columns inside of that grid that appears when you click on the +
(e.View as GridView).Columns["myHiddenColumn"].Visible = false;
(e.View as GridView).Columns.Add(new GridColumn() { Name = "AddColumn", Caption = "Name To Display", Visible = true, FieldName = "DataField"});
(e.View as GridView).Columns["DataField"].OptionsColumn.AllowEdit = false;
(e.View as GridView).Columns["DataField"].OptionsColumn.AllowFocus = false;
(e.View as GridView).Columns["DataField"].OptionsColumn.ReadOnly = true;
}
}
}
I think all you need to do is create a second grid view for your details. If you haven't already done this, do the following:
In your grid designer, click "Retrieve Details" if you have not already done so. This will cause the designer to recognize that you have a second level in your bound object:
Once you see the second layer, now you need a new grid view for it. Click on "Click here to change view" and select "Create a new view" and pick "GridView."
Now you will see both grid views from the designer, and clicking on one or the other will change the context of the menus to the left:
For example, if you have gridView2 selected, when you click on the "Layout" menu, it will show the current layout for your detail grid rather than the master grid. From here, you can remove or add columns as you see fit. Likewise, from the "Columns" menu you will see the new columns (you may have to add them to the view by dragging them over), and you can change the Caption property to change the text of the title.
I suggest you use the Data Annotation attributes with properties of your data-classes to declare how you data should be displayed in GridControl:
To skip column generation for the specific property you can mark this property with the <DisplayAttribute(AutoGenerateField := false)> declaration.
To prevent column from displaying you can mark this property with the <DisplayAttribute(Order := -1)> declaration. Later, user can show this column via Column Chooser UI.
To specify the column caption use the <DisplayAttribute(Name := "YOUR CAPTION")> declaration.
You can also control filtering/editing/formatting and validation capabilities.
Related Links:
Tutorial: Create and Manage Data in Code and Apply Data Annotation Attributes
Video Tutorial: Create and Manage Data in Code and Apply Data Annotation Attributes

Dojo EnhancedGrid and programmatic selection

Here's my problem: in my application I have a Dojo EnhancedGrid, backed up by an ItemFileReadStore. The page flow looks like this:
The user selects a value from a selection list.
The item from the list is posted on a server and then the grid is updated with data from the server (don't ask why, this is how it's supposed to work)
The new item is highlighted in the grid.
Now, the first two steps work like a charm; however, the third step gave me some headaches. After the data is successfully POSTed to the server (via dojo.xhrPost() ) the following code runs:
myGrid.store.close();
myGrid._refresh();
myGrid.store.fetch({
onComplete : function(items) {
for ( var i = 0; i < items.length; i++) {
if (items[i].documentType[0].id == documentTypeId) {
var newItemIndex = myGrid.getItemIndex(items[i]);
exportMappingGrid.selection.deselectAll();
exportMappingGrid.selection.addToSelection(newItemIndex);
}
}
}
});
Now, the selection of the grid is updated (i.e. the selection object has a selectedIndex > 0), but visually there's no response, unless I hover the mouse over the "selected" row. If I remove the .deselectAll() line (which I suspected as the culprit) then I sometimes end up with two items selected at once, although the grid selectionMode attribute is set to single.
Any thoughts on this one?
Thanks a lot.
You need to use setSelected(), like so
exportMappingGrid.selection.setSelected(newItemIndex, true);
The second parameter is true to select the row, false to unselect it.
This is what works for me:
grid.selection.clear();
grid.selection.addToSelection(newItemIndex);
grid.selection.getFirstSelected();
Jon