Julian Gold
Julian Gold

Reputation: 1286

Forcing list box to update in MVVM

I have a listbox which contains lines of a script file to be executed. I intend breakpoint lines in the script to show up red, so in the style for the list box container I've got

<DataTrigger Value="True">
    <DataTrigger.Binding>
        <MultiBinding Converter="{StaticResource IsBreakpointLineConverter}">
            <Binding Path="DataContext" ElementName="scriptListBox"/>
            <Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)"/>
        </MultiBinding>
    </DataTrigger.Binding>
    <Setter Property="Foreground" Value="Red"/>
</DataTrigger>

The converter IsBreakpointLineConverter takes as the first argument my ViewModel, which has a method GetCommandAtLineNumber( int line ), and as a second argument the line number of the script command:

public class IsBreakpointLineConverter : IMultiValueConverter
{
    public object Convert( object [] values, Type targetType, object parameter, CultureInfo culture )
    {
        ScriptViewModel svm = (ScriptViewModel)values[0];
        int line = (int)values[1];
        ScriptCommand command = svm.GetCommandAtLine( line );
        return command != null && command.IsBreakpoint;
    }

    public object[] ConvertBack( object value, Type[] targetType, object parameter, CultureInfo culture )
    {
        throw new NotSupportedException();
    }
}

My ViewModel also implements a command to toggle the breakpoint status of a command

    private void toggleBreakpoint( object arg )
    {
        Debug.Assert( _selectedCommand != null );

        SelectedLineIsBreakpoint = !SelectedLineIsBreakpoint;
    }

and this works great, but it doesn't update the ListBox. If I select a new script, and then the old one, the breakpoint line shows in red; ergo, I need a way to ensure the list box contents are refreshed when a breakpoint line is toggled. Now stuck!

EDIT if I add the following hideous hack to toggleBreakpoint, things work as intended:

    private void toggleBreakpoint( object arg )
    {
        Debug.Assert( _selectedCommand != null );

        SelectedLineIsBreakpoint = !SelectedLineIsBreakpoint;
        _scriptLines = new List<string>( _scriptLines );
        OnPropertyChanged( "ScriptLines" );
    }

Upvotes: 0

Views: 245

Answers (1)

Michael Gunter
Michael Gunter

Reputation: 12811

You want for the UI to change when the IsBreakpoint property of ScriptCommand changes, but you don't have anything bound to this property. The ItemsSource property of your ListBox is presumably bound to a collection of either Model or ViewModel objects. Is it a collection of ScriptCommand objects? You could turn the IsBreakpoint property into a dependency property and bind directly to that property from the UI with something like this:

<DataTrigger Binding="{Binding IsBreakpoint}" Value="True">
    <Setter Property="Foreground" Value="Red"/>
</DataTrigger>

If adding dependency properties to ScriptCommand breaks your architecture, you should add a new ViewModel class to represent this.

Upvotes: 1

Related Questions