IsSelected property of ViewModel bound to ListBox, Only FIRST item selection works?

本小妞迷上赌 提交于 2019-12-13 03:11:18

问题


I have a MeetingViewModelList bound to a DataGrid. Each MeetingViewModel has a DocumentViewModelList bound to a ListBox within the DataGrid`s DataGridTemplateColumn.

The IsSelected property of the DocumentViewModel is bound to the ListBox`s Item property IsSelected.

I get no binding errors in the output console.

The delete document button in the DocumentViewModel checks in its CanExecute Method this:

private bool CanDeleteDocument()
        {
            return _isSelected;
        }

When I select the FIRST Item in the ListBox, the Delete button is enabled. When I selected the 2nd,3rd etc. Item in the ListBox the Delete button is ALWAYS disabled.

I try to paste only the important code and cropped other stuff:

I have just tried to rebuild the scenario with just a ListBox -not being part of a DataGrid- and I get the same behavior :/

I would be pleased about any hint :)

XAML:

<DataGrid  VirtualizingStackPanel.VirtualizationMode="Recycling"
                ScrollViewer.CanContentScroll="False"                  
                CanUserResizeRows="True"                
                VerticalScrollBarVisibility="Auto"
                ItemsSource="{Binding MeetingViewModelList}"
                AutoGenerateColumns="False" 
                x:Name="DailyGrid" 
                Height="580"
                SelectionMode="Single"
                CanUserSortColumns="False"
                Background="#FF2DCE2D"               
                CanUserAddRows="False" 
                HeadersVisibility="All"
                RowHeaderWidth="40"
                RowHeight="200" >                        


                        <!--Content-->
                        <DataGridTemplateColumn Width="0.5*" Header="Content">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Helper:RichTextBox LostFocus="RTFBox_LostFocus" VerticalScrollBarVisibility="Auto" x:Name="RTFBox" Text="{Binding Content,IsAsync=True}" AcceptsReturn="True" AutoWordSelection="False" AllowDrop="False" SelectionBrush="#FFAC5BCB" HorizontalScrollBarVisibility="Hidden">
                                        <Helper:RichTextBox.TextFormatter>
                                            <Helper:RtfFormatter />
                                        </Helper:RichTextBox.TextFormatter>
                                    </Helper:RichTextBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

                        <!--Documents-->
                        <DataGridTemplateColumn Visibility="{Binding Source={StaticResource spy}, Path=DataContext.DocumentsVisible}" IsReadOnly="True" Width="125" Header="Attachments">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>                                    
                                        <StackPanel Background="Green" DataContext="{Binding DocumentViewModelList}" Orientation="Vertical" >
                                            <ListBox SelectionMode="Single" VirtualizingStackPanel.IsVirtualizing="False"
                                                Height="100"                                               
                                                Width="Auto"
                                                Focusable="True"
                                                ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                                                ScrollViewer.VerticalScrollBarVisibility="Auto" 
                                                Grid.Row="1" 
                                                Name="documentListBox"
                                                BorderThickness="1"                                                
                                                ItemsSource="{Binding}"
                                                Visibility="{Binding ElementName=documentListBox,Path=HasItems, Converter={StaticResource boolToVisibilityConverter}}"
                                                >
                                                <ListBox.ItemTemplate>
                                                    <DataTemplate>
                                                        <StackPanel>                                                          
                                                            <TextBlock Text="{Binding Path=Name}" />
                                                        </StackPanel>
                                                    </DataTemplate>
                                                </ListBox.ItemTemplate>
                                                <ListBox.ItemContainerStyle>                                                  
                                                        <Style TargetType="{x:Type ListBoxItem}">
                                                            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />                                                      
                                                        </Style>      
                                                </ListBox.ItemContainerStyle>                                        
                                            </ListBox>
                                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
                                                <Button Command="{Binding Path=DeleteDocumentCommand}" HorizontalAlignment="Stretch" Content="Delete" />
                                                <Button Command="{Binding Path=AddDocumentCommand}" HorizontalAlignment="Stretch" Content="Add" />
                                                <Button Command="{Binding Path=OpenDocumentCommand}" HorizontalAlignment="Stretch" Content="Open" />                                             
                                            </StackPanel>
                                        </StackPanel>                                  
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                    </DataGrid.Columns>
                </DataGrid>

ReportingViewModel(Controller):

public class ReportingViewModel : ViewModelBase
    {   
        private ObservableCollection<MeetingViewModel> _meetingViewModelList;      

        public ReportingViewModel ()
        {            

        }  

        public ObservableCollection<MeetingViewModel> MeetingViewModelList
        {
            get { return _meetingViewModelList; }
            set
            {
                _meetingViewModelList= value;
                this.RaisePropertyChanged("MeetingViewModelList");
            }
        }         
    }

MeetingViewModel:

public class MeetingViewModel: ViewModelBase
{
    private ObservableCollection<DocumentViewModel> _documentViewModelList = new ObservableCollection<DocumentViewModel>();
    private Meeting _meeting;

    public MeetingViewModel(Meeting meeting)
    {
        _meeting= meeting;

        _meeting.Documents.ForEach(doc => DocumentViewModelList.Add(new DocumentViewModel(doc)));                                   
    }

    public ObservableCollection<DocumentViewModel> DocumentViewModelList
    {
        get { return _documentViewModelList; }
        set
        {
            _documentViewModelList = value;
            this.RaisePropertyChanged("DocumentViewModelList");
        }
    } 

    public string Content
    {
        get { return _meeting.Content; }
        set
        {
            if (_meeting.Content == value)
                return;

            _meeting.Content = value;
            this.RaisePropertyChanged("Content");
        }


   }     
    }

DocumentViewModel:

public class DocumentViewModel : ViewModelBase
{
    private Document _document;

    private RelayCommand _deleteDocumentCommand;
    private RelayCommand _addDocumentCommand;
    private RelayCommand _openDocumentCommand;

    public DocumentViewModel(Document document)
    {
        _document = document;
    }

    private void DeleteDocument()
    {
        throw new NotImplementedException();
    }

    private bool CanDeleteDocument()
    {
        return _isSelected;
    }

    private void AddDocument()
    {

    }

    private void OpenDocument()
    {

    }

    public RelayCommand DeleteDocumentCommand
    {
        get { return _deleteDocumentCommand ?? (_deleteDocumentCommand = new RelayCommand(() => DeleteDocument(), () => CanDeleteDocument())); }
    }

    public RelayCommand AddDocumentCommand
    {
        get { return _addDocumentCommand ?? (_addDocumentCommand = new RelayCommand(() => AddDocument())); }
    }

    public RelayCommand OpenDocumentCommand
    {
        get { return _openDocumentCommand ?? (_openDocumentCommand = new RelayCommand(() => OpenDocument())); }
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected == value)
                return;

            _isSelected = value;
            this.RaisePropertyChanged("IsSelected");
        }
    }

    public string Name
    {
        get { return _document.DocumentName; }
        set
        {
            if (_document.DocumentName == value)
                return;

            _document.DocumentName = value;
            this.RaisePropertyChanged("Name");
        }
    }       
}

回答1:


I'm sure it can be made to work this way, but wouldn't it be easier to just track the selected item in another way? For example, binding to an ICollectionView (for example ListCollectionView) that wraps the actual collection allows the use of the built-in selection tracking mechanism (CurrentItem of the ICollectionView). Alternatively, you could use SelectedValue and SelectedValuePath of the ListBox.




回答2:


I think the problem is that delete command does not know that selection has changed.

Add CanDeleteChanged to the relay command and raise it after this.RaisePropertyChanged("IsSelected"). I've had similar problems with Prism apps before.

EDIT. Infact you should add the CanDeleteChanged and put a breakpoint in it and see if its being called when you expect it to or not anyway.

Sorry I meant CanExecuteChanged event on the Delete relay command. Your code should have the declaration of a relay command somewhere. For the sake of info here it is

public class RelayCommand : ICommand { #region Fields

readonly Action<object> _execute;
readonly Predicate<object> _canExecute;        

#endregion // Fields

#region Constructors

public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
    if (execute == null)
        throw new ArgumentNullException("execute");

    _execute = execute;
    _canExecute = canExecute;           
}
#endregion // Constructors

#region ICommand Members

[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
    return _canExecute == null ? true : _canExecute(parameter);
}

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

public void Execute(object parameter)
{
    _execute(parameter);
}

#endregion // ICommand Members

}



来源:https://stackoverflow.com/questions/3695719/isselected-property-of-viewmodel-bound-to-listbox-only-first-item-selection-wor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!