Monthly Archives: January 2010

ClickOnce Exception reading manifest

I’ve had ClickOnce blow up on me on more than one occasion and I have to confess that it really does irk me. So much time wasted on what must be a bug in Visual Studio. To be precise VS 2005 (yep I still have projects in version 2.0 of the framework).

So the problem is that after publishing the clickOnce application fails with this error:
Exception reading manifest from<fullPath and name to manifest here>: the manifest may not be valid or the file could not be opened.
+ Deployment manifest is not semantically valid.
+ Deployment manifest cannot specify minimumRequiredVersion for online applications.

I also noticed that the Updates button on the publish tab of my start-up project was disabled – tsk!  So I compared  the csproj file of a working project and found that the line below the PublishUrl had the value of false in it.  So I changed it to true.

<PublishUrl><fullPath and name to manifest here></PublishUrl>
<Install>true</Install>

This fixed the problem.

How to get a ListView with expandable controls to resize

I created a ListView and used an expandable control for each of the ListView’s items. Everything was fine until I noticed that after collapsing an item the ListView did not resize. Resizing worked fine in the other direction, i.e. the Listview would grow in size when an item was expanded. I thought that I was going to have to do all sorts of jiggery pokery with MeasureOverride or the such like but actually the solution was really simple.

Just set the ItemsPanel to a type that automatically resizes:

<ListView.ItemsPanel>
  <ItemsPanelTemplate>
    <StackPanel/>
  </ItemsPanelTemplate>
</ListView.ItemsPanel>

So here is my ListView in its entirety:

<ListView x:Name="lvMenus" AllowDrop="True" ItemContainerStyle="{DynamicResource ItemContStyle}"
    		HorizontalAlignment="Stretch">
	<ListView.ItemsPanel>
		<ItemsPanelTemplate>
			<StackPanel/>
		</ItemsPanelTemplate>
	</ListView.ItemsPanel>
	<ListView.View>
		<GridView>
			<GridViewColumn Header="Titles">
				<GridViewColumn.CellTemplate>
					<DataTemplate>
						<spEtr:Inspector
					          AssetId="{Binding Id, Mode=OneWay}"
						  LongTitle="{Binding LongTitle, Mode=TwoWay}"
						  LongTitleChanged="Inspector_LongTitleChanged"
						  LongTitleLostFocus="Inspector_LongTitleLostFocus"
						  LongTitleGotFocus="Inspector_LongTitleGotFocus"
						  ShortTitle="{Binding ShortenedTitle, Mode=TwoWay}"
						  ShortTitleChanged="Inspector_ShortTitleChanged"
						  ShortTitleFocused="Inspector_ShortTitleFocused"
						  ShortTitleLostFocus="Inspector_ShortTitleLostFocus"
						  ExpanderClicked="Inspector_ExpanderClicked"
						  LongTitleErrorStatusChanged="Inspector_LongTitleErrorStatusChanged"
							/>
					</DataTemplate>
				</GridViewColumn.CellTemplate>
			</GridViewColumn>
		</GridView>
	</ListView.View>
</ListView>

WPF Using a trigger when Validation has error

There is much documentation out there regarding how to use ValidationRules together with an ErrorTemplate in order to highlight invalid user data. However, I found it a little trickier to find out how to trigger some other kind of behaviour.

Here is my scenario:
I have two text boxes, the second of which is collapsed unless a validation error occurs in the first text box. This seems like pretty much a run of the mill scenario but it was a little trickier to get working than simply putting a red border round the first text box.

I put all the validation and triggers in a Style.  Here is the XAML describing the two text boxes:

<StackPanel Name="ExpanderStackPnl" MinWidth="440">
  <Expander x:Name="TitleExpander"
                      Header="{Binding ElementName=InspectorRoot, Path=LongTitle}"
              Collapsed="TitleExpander_Collapsed" Expanded="TitleExpander_Expanded">
    <StackPanel Margin="5,5,5,5" x:Name="StackInsideExpander">
		   <spCntrls:SportTitle x:Name="spTitle"
                             SpLabel="Desired title (fits on most platforms):"
                             Style="{StaticResource LongTitleStyle}"
                             TitleChanged="LongTitle_Changed"
                             LostFocus="LongTitle_LostFocus"
                             ErrorStatusChanged="LongTitle_ErrorStatusChanged"
                              GotFocus="LongTitle_GotFocus">

          <spCntrls:SportTitle.UserText>
            <Binding Path="LongTitle"
                              ElementName="InspectorRoot"
                              UpdateSourceTrigger="PropertyChanged"
                              NotifyOnValidationError="True"
                             Mode="TwoWay">
              <Binding.ValidationRules>
                <rules:FitsAllValidationRule/>
              </Binding.ValidationRules>
            </Binding>
          </spCntrls:SportTitle.UserText>
        </spCntrls:SportTitle>

        <spCntrls:SportTitle x:Name="spShortTitle"
                             SpLabel="Abbreviated Title (must fit ALL platforms)"
                             Style="{StaticResource ShortTitleStyle}"
                             TitleChanged="ShortTitle_Changed"
                             GotFocus="ShortTitle_GotFocus"
                             LostFocus="ShortTitle_LostFocus">
          <spCntrls:SportTitle.UserText>
            <Binding Path="ShortTitle"
                              ElementName="InspectorRoot"
                              UpdateSourceTrigger="PropertyChanged"
                              NotifyOnValidationError="True"
                             Mode="TwoWay">
              <Binding.ValidationRules>
                <rules:FitsAllValidationRule/>
              </Binding.ValidationRules>
            </Binding>
          </spCntrls:SportTitle.UserText>
        </spCntrls:SportTitle>
     </StackPanel>
   </Expander>
</StackPanel>

As you can see, I have attached a style to each of them and that is where the behaviour is described.  I used a GlobalDictionary to store the styles creating a namespace to refer to the class (named Inspector) where my text boxes reside.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:edtr="clr-namespace:BBCNewsI.Cps2Dtext.SportEditor"
    xmlns:spCntrls="clr-namespace:BBCNewsI.Cps2Dtext.SportEditor.Controls">

The XAML which is of interest is in the style named ShortTitleStyle. Using a DataTrigger you can trigger on changes to another control:

<DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=spTitle}" Value="true">
	<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=spTitle}" Value="false">
	<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>

The thing that I found interesting is that a sibling control is simply referred to by its name, there is no need for any fancy namespace references or Ancestor like binding.

You might have noticed that these controls are inside an expander. This creates in interesting problem when there is an error and the expander is collapsed, namely that you can still see the border of the error template! To get round this, I used another DataTrigger with a dependency property which indicates the expanded state of the expander to set the error template to null:

<DataTrigger Binding="{Binding Path=TitleExpanded,
        RelativeSource={RelativeSource AncestorType={x:Type spCntrls:Inspector}}}"
                   Value="False">
  <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
 </DataTrigger>

<DataTrigger Binding="{Binding Path=TitleExpanded,
        RelativeSource={RelativeSource AncestorType={x:Type spCntrls:Inspector}}}"
                   Value="True">
   <Setter Property="spCntrls:SportTitle.ToolTip"
                Value="Enter title for scene, both text fields usually have the same text " +
                      "unless the desired title is too long to fit on all platforms"/>
</DataTrigger>

Here are both styles that have been applied to the text boxes in their entirety:

<Style x:Key="LongTitleStyle" TargetType="{x:Type spCntrls:SportTitle}">
    <Setter Property="Validation.ErrorTemplate">
      <Setter.Value>
        <ControlTemplate x:Name="InspectorErrorTemplate">
          <StackPanel Orientation="Vertical">
            <Border BorderBrush="Goldenrod" BorderThickness="1">
              <AdornedElementPlaceholder Name="adornerPlaceholder"/>
            </Border>
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=TitleExpanded,
        RelativeSource={RelativeSource AncestorType={x:Type spCntrls:Inspector}}}"
                   Value="False">
        <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
      </DataTrigger>

      <DataTrigger Binding="{Binding Path=TitleExpanded,
        RelativeSource={RelativeSource AncestorType={x:Type spCntrls:Inspector}}}"
                   Value="True">
        <Setter Property="spCntrls:SportTitle.ToolTip"
                Value="Enter title for scene, both text fields usually have the same " +
			"text unless the desired title is too long to fit on all platforms"/>
     </DataTrigger>

      <Trigger Property="Validation.HasError" Value="true">
        <Setter Property="spCntrls:SportTitle.UserTextForeground" Value="Maroon"/>
        <Setter Property="spCntrls:SportTitle.HasError" Value="true"/>
        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
          Path=(Validation.Errors)[0].ErrorContent}"/>
      </Trigger>
      <Trigger Property="Validation.HasError" Value="false">
        <Setter Property="spCntrls:SportTitle.HasError" Value="false"/>
      </Trigger>
    </Style.Triggers>
  </Style>

  <!-- Style for short version of the title -->
  <Style x:Key="ShortTitleStyle" BasedOn="{StaticResource LongTitleStyle}"
							TargetType="{x:Type spCntrls:SportTitle}">
    <Setter Property="Validation.ErrorTemplate">
      <Setter.Value>
        <ControlTemplate x:Name="InspectorErrorTemplate">
          <StackPanel Orientation="Vertical">
            <Border BorderBrush="Red" BorderThickness="1">
              <AdornedElementPlaceholder Name="adornerPlaceholder"/>
            </Border>
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
    <Style.Triggers>
      <Trigger Property="Validation.HasError" Value="true">
        <Setter Property="spCntrls:SportTitle.UserTextForeground" Value="Red"/>
        <Setter Property="ToolTip" Value="Alternative title is not short enough"/>
      </Trigger>

      <DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=spTitle}" 
               Value="true">
        <Setter Property="Visibility" Value="Visible"/>
      </DataTrigger>
      <DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=spTitle}" 
               Value="false">
        <Setter Property="Visibility" Value="Collapsed"/>
      </DataTrigger>
    </Style.Triggers>
  </Style>

Unauthorised operation whilst saving remote configuration file

I encountered an interesting problem whilst trying to save changes to a configuration file that is not on the local machine.

When calling Configuration.Save(), dot net creates a new copy of the configuration file which has the changed information, the original is hived away to a temp location and it’s security permissions are then copied to the new file before the original is deleted and the new file renamed to be the same as the old file.

From MSDN documentation:

When ‘Creator Owner’ is listed in the ACL (Access Control List) of the directory containing the configuration file, the current user of Save becomes the new owner of the file and inherits the permissions granted to ‘Creator Owner’. This results in an elevation of privileges for the current user and a removal of privileges for the previous owner.

Deeper down Configuration.Save() calls

System.Configuration.Internal.WriteFileContext.DuplicateFileAttributes(String source, String destination)

Take a look at the function:

private void DuplicateTemplateAttributes(string source, string destination)
{
   if (this.IsWinNT)
   {
     FileSecurity accessControl = File.GetAccessControl(source, AccessControlSections.Access);
     accessControl.SetAccessRuleProtection(accessControl.AreAccessRulesProtected, true);
     File.SetAccessControl(destination, accessControl);
   }
  else
  {
    FileAttributes FileAttributes fileAttributes = File.GetAttributes(source); File.SetAttributes(destination, fileAttributes );
  }
}

The work around is to use Configuration.SaveAs and then copy this version over the original file which is almost the same as the Save method but doesn’t require taking ownership of the file or copying the permissions to the new file.