wpflistviewdata-bindingdatatemplatelistviewitem

Display only one TextBox which is bound to selected item from ListView


I have a ListView which is bound to an ObservableCollection I have added a DataTemplate to a ListView to bind item with TextBox in purpose to Rename selectedItem using Rename from ContextMenu:

View

        <ListView DockPanel.Dock="Left"
                  Background="MidnightBlue"
                  Width="140"
                  SelectedItem="{Binding SelectedNotebook, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  ItemsSource="{Binding Notebooks}"
                  x:Name="notebooksList"
                  SelectionChanged="notebooksList_SelectionChanged"
                  SelectionMode="Single">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <uc:DisplayNotebook Notebook="{Binding}">
                            <uc:DisplayNotebook.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="Rename"
                                              Command="{Binding Source={StaticResource vm}, Path=EditCommand}"
                                              CommandParameter="{Binding SelectedNotebook}"/>
                                    <MenuItem Header="Delete"
                                              Command="{Binding Source={StaticResource vm}, Path=DeleteNotebookCommand}"
                                              CommandParameter="{Binding SelectedNotebook}"/>
                                </ContextMenu>
                            </uc:DisplayNotebook.ContextMenu>
                        </uc:DisplayNotebook>
                        <TextBox Text="{Binding Name, Mode=TwoWay}"
                                 Visibility="{Binding Source={StaticResource vm}, Path=IsVisible}"
                                 x:Name="notebookTextBox">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="LostFocus">
                                    <i:InvokeCommandAction Command="{Binding Source={StaticResource vm}, Path=EndEditingCommand}"
                                                           CommandParameter="{Binding}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </TextBox>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

ViewModel

        public async void StopEditingNotebook(Notebook notebook)
        {
            IsVisible = Visibility.Collapsed;
            await DatabaseHelper.Update(notebook);
            GetNotebooks();
        }

        public async void StopEditingNote (Note note)
        {
            IsVisible = Visibility.Collapsed;
            await DatabaseHelper.Update(note);
            GetNotes();
        }

Commands

  public class EndEditingCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public NotesVM ViewModel { get; set; }

        public EndEditingCommand(NotesVM vm)
        {
            ViewModel = vm;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            Notebook notebook = parameter as Notebook;
            if (notebook != null)
                ViewModel.StopEditingNotebook(notebook);
        }
    }
public class EditCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public NotesVM ViewModel { get; set; }

        public EditCommand(NotesVM vm)
        {
            ViewModel = vm;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            ViewModel.StartEditing();
        }
    }

I'd like to Rename only one item at once by popping up one TextBox instead of all TextBoxes in the same time(this what is happening currently due to bound TextBox in DataTemplate).

I was wondering about finding an ID of selectedItem and then somehow display only this particular TextBox.

Do you have any ideas on this matter? Thanks for help in advance


Solution

  • You can use a MultiDataTrigger to toggle the Visibility of the TextBox. The conditions are IsSelected and IsVisible from your view model.

    Alternatively (recommended), spend your item model an IsEditEnabled property (or move and rename the IsVisible property to the item model).

    Currently, every item binds to the same IsVisible property of the same ViewModel instance.
    Instead, each item must bind to its own property (that's why the property should be defined in the item model).

    Note, a member named with the prefix "is" is expected to return a boolean. In your case it would be semantically correct to name the property Visibility and not IsVisible.

    Additionally, the CommandParameter binding inside the ContextMenu looks wrong too. It must be

    <ContextMenu>
      <MenuItem CommandParameter="{Binding}"/>
    </ContextMenu>