Wix Interactions with Conditions, Properties & Custom Actions

I am having a problem with a setting the enabled state of a button on a Dialog. The button in question is defined as:

<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)">
<Condition Action="disable">Validated = 0</Condition>
<Condition Action="enable"><![CDATA[Validated <> 0]]></Condition>
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>

The property Validated starts out at an initial value of 0, and as expected the next button starts out disabled.

<Property Id="Validated" Value="0"/>

The property itself is modified through a Custom Action on another button.

<Control Id="PerformValidation" Type="PushButton" X="225" Y="75" Width="50" Height="20" Text="Validate">
<Publish Event="DoAction" Value="ValidateDB">1</Publish>
</Control>

With a stripped down version of the Custom Action like:

[CustomAction]
public static ActionResult ValidateDatabase(Session session)
{
session.Log("Begin ValidateDatabase");
session["Validated"] = "1";
return ActionResult.Success;
}

The problem I face is that the Next button does not re-enable itself after the Custom Action has run. I can confirm that the CA does run, and the property is successfully set. The UI will update if I do some other action that causes it to refresh, e.g. go back a page then forward to this page again and the Next button will be enabled.

Any ideas on how to refresh a buttons state after a Custom Action?


Solution 1:

http://www.mail-archive.com/[email protected]/msg05097.html gives an solution to republish the properties that were changed in the custom action immediately after it.

Here is an example of how I have gotten it to work in my code:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <Binary Id="ConnectionStringExtension.dll" SourceFile="$(var.ConnectionStringExtension.TargetDir)$(var.ConnectionStringExtension.TargetName).CA.dll" />
        <CustomAction Id="MyCustomAction" BinaryKey="ConnectionStringExtension.dll" DllEntry="VerifyConnectionString" Execute="immediate"  />

        <UI>
            <Dialog Id="ConnectionStringDlg" Width="370" Height="270" Title="Database Settings - [ProductName]" NoMinimize="yes">
                <Control Id="ConnectionStringLabel" Type="Text" X="45" Y="73" Width="100" Height="15" TabSkip="no" Text="&amp;Connection String:" />
                <Control Id="ConnectionStringEdit" Type="Edit" X="45" Y="95" Width="220" Height="15" Property="CONNECTION_STRING" Text="{200}" />
                <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back">
                </Control>
                <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next">
                    <Condition Action="enable"><![CDATA[CONNECTION_STRING <> "" AND CONNECTION_STRING_VALID = "1"]]></Condition>
                    <Condition Action="disable"><![CDATA[CONNECTION_STRING = "" OR CONNECTION_STRING_VALID = "0"]]></Condition>
                </Control>
                <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
                    <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
                </Control>
                <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
                <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
                    <Text>Please enter database configuration</Text>
                </Control>
                <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
                <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
                    <Text>{\WixUI_Font_Title}Database Settings</Text>
                </Control>
                <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
              <Control Id="VerifyButton" Type="PushButton"  Width="56" Height="16" X="45" Y="118" Text="Verify">
                <Publish Event="DoAction" Value="MyCustomAction">1</Publish>
                <Publish Property="TEMP_VERIFIED" Value="[CONNECTION_STRING_VALID]">1</Publish>
                <Publish Property="CONNECTION_STRING_VALID" Value="[TEMP_VERIFIED]" />
              </Control>
            </Dialog>
        </UI>
    </Fragment>
</Wix>

The CustomAction sets the value of CONNECTION_STRING_VALID to either 1 or 0 depending if it is valid or not and I have defined elsewhere that by default its value is 0

<Property Id="CONNECTION_STRING_VALID" Value="0" />

Now when I click my verify button if the string is valid the next button is enabled

Solution 2:

This is a well-known limitation of Windows Installer. The state of the dialog doesn't change until you refresh it in any other way, for instance, moving back and forward, as you correctly mentioned.

The workaround here is to have two identical dialogs, DialogA and DialogB. The PerformValidation button on DialogA will perform validation as it does right now and call DialogB (as NewDialog). The same way, the PerformValidation button on DialogB will also perform validation and call DialogA. Thus, you'll have the dialogs to be loaded each time you run validation and button state will be correctly displayed. The user won't suspect anything, because he/she will only see the same dialog. :-)

The idea is described better in detail here. It is called "twin dialogs".

Hope this helps.