Question

I have a weird problem with a button's Command binding not being updated...

I have an app written with MvvmLight, that allows users to maintain a list of medical systems. These systems are built from templates (ie a template might specify two cameras, one framegrabber and so on, as well as details about what each of these parts should contain). If the template is modified, the systems can be upgraded to use the new template. Both the system window and the templates window are modeless, so the templates can be modified while a system is being viewed. The templates window view model sends out a message if the template is updated, so that any open system windows can react accordingly.

The system view holds a Border that is used to warn the user when they need to upgrade the system. The Visibility of the Border is bound to a bool property on the system entity that compares the system's revision number with the latest revision number of the underlying template. If they are on the latest template revision, the Visibility is set to Collapsed, so they don't see the contents.

If the system uses an older revision, the Border is visible, and the content contains a message informing them of the need to upgrade, as well as button that does the upgrade. I have three scenarios with this border and button...

1) If the system uses an out-of-date revision when the window is opened, the border is shown, and the button is visible. If the template is modified, the message updates correctly to show the new number, and the button remains visible. This is correct.

2) If the system was using the latest template revision when it was opened, then when the template is revised, the border is displayed correctly, the message is updated correctly, and the button is enabled. Again, this is correct, as long as I close the system window afterwards.

3) However, if I click the update button, then after the system is upgraded and the border is hidden, I update the template again, then when the border is redisplayed, the button is disabled. I tried removing all the logic from the CanExecute method and just returning true, so the button should be enabled, but it isn't. I have to close the system window and reopen it to enable the button.

I tried adding an event to the view model, which I raised whenever the template was updated. I caught this event in the view and manually refreshed the button's command binding. However, this did NOT cause the CanExecute method to be called again, and the button remained disabled.

I realise that this is all a bit confusing, and hard to debug without seeing the whole thing, but I'm hoping someone might be able to give me some clues. In case it helps, here is the relevant code...

First, the XAML for the border, message and button...

<Border Visibility="{Binding Converter={StaticResource BoolToVisibilityVC}, Path=NotUsingLatestDhrTemplate, ConverterParameter=true}"
        HorizontalAlignment="Stretch"
        Margin="3"
        Grid.Row="3"
        BorderBrush="Red"
        BorderThickness="2"
        Background="#FFFFEBEB">
  <Grid Margin="3"
        gridHelper:GridHelper.GridRows="*,Auto">
    <WrapPanel>
      <TextBlock Text="This PCR uses template revision "
                  VerticalAlignment="Center" />
      <TextBlock Text="{Binding TemplateRevisionForThisDhr}"
                  VerticalAlignment="Center" />
      <TextBlock Text=", but the current template revision is "
                  VerticalAlignment="Center" />
      <TextBlock Text="{Binding LatestTemplateRevisionForThisPartDefinitionType}"
                  VerticalAlignment="Center" />
      <telerik:RadButton Name="UpdateDhrButton"
                          Click="UpdateDhrButton_OnClick"
                          Command="{Binding Path=DataContext.UpdateDhrCommand, ElementName=DhrViewX}"
                          Margin="0,0,10,0"
                          HorizontalAlignment="Right"
                          VerticalAlignment="Stretch"
                          IsEnabledChanged="UpdateDhrButton_IsEnabledChanged">
        <StackPanel Orientation="Horizontal"
                    Margin="1">
          <Image Margin="0,0,3,0"
                  Width="16"
                  Height="16"
                  Source="/Images;component/Images/battery.png" />
          <TextBlock>Update PCR</TextBlock>
        </StackPanel>
      </telerik:RadButton>
    </WrapPanel>
  </Grid>
</Border>

There isn't any point in showing the CanExecute method, as all it contains is "return true;" at the moment!

It looks as if there is some odd interaction going on between the visibility of the border and the enabled state of the button, and this seems to be overriding the CanExecute method's result.

Anyone any ideas? Please feel free to ask if I forgot to add anything important here. Thanks in advance.

Était-ce utile?

La solution

Well, whilst I'm not 100% sure what the problem was, I'm pretty sure I know, so will post it in case it helps anyone else.

The problem only seemed to occur after the button had been disabled at some point. It seems that as long as I had a CanExecute method on the command, then even if this always returned true, the button would still be temporarily disabled during the binding process. If that happened when the border control that contained the button had its Visibility set to Collapsed, then the button would not be enabled, irrespective of what the CanExecute method returned.

I worked around this by removing the CanExecute method, and hiding the button when I didn't want it to be clicked. Then, every time the border was made visible, I manually set the button's IsEnabled property to true.

That worked in this particular scenario, as usage of the button was permissions based, so if they aren't allowed to click it, it's fine not to let them see it. It would still cause problems in other scenarios though, and I'm not sure how you would get around it.

Hope this helps someone.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top