Search code examples
wpfdata-bindingprismsoftware-design

Updated value not reflecting in UI in WPF


I'm trying to populate and navigation panel dynamicaly in a ListView

<ListView Background="Transparent" HorizontalAlignment="Center" x:Name="viewItemControl" ItemsSource="{Binding Views}">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Button Style="{StaticResource PluginViewButton}" 
                        Command="{Binding ElementName=viewItemControl,Path=DataContext.NavigateCommand}" 
                        CommandParameter="{Binding ViewName}" 
                        BorderThickness="{Binding Path = ViewObj.DataContext.IsSelected, Converter={StaticResource BoolToThicknessConverter},Mode=OneWay}">
                    <Button.Content>
                        <Grid Background="White">
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition Height="15"/>
                            </Grid.RowDefinitions>
                            <Image Grid.Row="0" Source="{Binding Icon, Mode=OneTime}"></Image>
                            <TextBlock Grid.Row="1" Text="{Binding DisplayableName}" HorizontalAlignment="Center"/>
                        </Grid>
                    </Button.Content>
                </Button>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Focusable" Value="false"/>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>

The list view is binded to a collection of ViewInfo Objects

public class ViewInfo
{
    public ViewInfo(IPluggableView view)
    {
        ViewName = view.ViewName;
        DisplayableName = view.DisplayableName;
        DisplayRank = view.DisplayRank;
        Icon = view.Icon;
        ViewModelType = view.ViewModelType;
        ViewObj = view;
    }
    public IPluggableView ViewObj { get; set; }
    public string ViewName { get; set; }
    public string DisplayableName { get; set; }
    public Type ViewModelType { get;set; }
    public int DisplayRank { get; set; }
    public BitmapSource Icon { get; set; }
}

The Interface IPluggableView is implemented by all of my usercontrols which are views

My viewmodel base class has a property IsSelected. Viewmodel class is implementing prism INavigationAware interface, so in OnNavigatedTo and OnNavigatedFrom functions i'm updating the IsSelected property.

I want my buttons border to be thicker when it's view is selected and it should go back to default when i navigate to another view as given below.

Navigation Panel

So i wrote BoolToThickness converter which simply returns 0.5 or 2 depending on the value.

The problem I face is that it's only updating once at Load time, then never updated after that eventhough i update IsSelected property.

I'm kind of sure that the UI is not getting the RaisePropertyChanged event. but i'm know sure how to solve this problem. If this is a design issue please help me rectify it.


Solution

  • You should define the ItemContainerStyle and trigger on IsSelected directly. To override the ControlTemplate is only necessary if you want to modify or remove the default highlight behavior:

    <ListView.ItemContainerStyle>
      <Style TargetType="ListViewItem">
        <Setter Property="BorderThickness"
                Value="1" />
        <Setter Property="BorderBrush"
                Value="Black" />
    
        <!-- Optional -->
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
              <Border Background="{TemplateBinding Background}" 
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}" 
                      Padding="{TemplateBinding Padding}">
                <ContentPresenter />
              </Border>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
    
        <!-- Change border thickness on item is selected -->
        <Style.Triggers>
          <Trigger Property="IsSelected" Value="True">
            <Setter Property="BorderThickness" Value="3" />
          </Trigger>
        </Style.Triggers>
      </Style>
    </ListView.ItemContainerStyle>
    

    Additionally you should bind the ListView.SelectedItem to your view model to control the current selection.

    But if you still want to use a value conveter then you should adjust the binding on the BorderThickness:

    <Button BorderThickness="{Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListViewItem}, Path=IsSelected, Converter={StaticResource BoolToThicknessConverter}}">