【问题标题】:IsSelected property of ViewModel bound to ListBox, Only FIRST item selection works?ViewModel 的Selected 属性是否绑定到ListBox,只有第一个项目选择有效?
【发布时间】:2010-09-12 17:07:06
【问题描述】:

我有一个绑定到 DataGridMeetingViewModelList。 每个 MeetingViewModel 都有一个 DocumentViewModelList 绑定到 DataGrid 的 DataGridTemplateColumn 内的 ListBox

DocumentViewModel 的 IsSelected 属性绑定到 ListBox 的 Item 属性 IsSelected。

我在输出控制台中没有遇到任何绑定错误。

DocumentViewModel 中的删除文档按钮检查其 CanExecute 方法:

private bool CanDeleteDocument()
        {
            return _isSelected;
        }

当我在 ListBox 中选择 FIRST 项时,删除按钮被启用。 当我选择列表框中的第 2、3 等项时,删除按钮始终处于禁用状态。

我尝试只粘贴重要的代码并裁剪其他内容:

我刚刚尝试仅使用 ListBox(不是 DataGrid 的一部分)来重建场景,但我得到了相同的行为:/

我会很高兴任何提示:)

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(控制器):

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");
        }
    }       
}

【问题讨论】:

    标签: wpf listbox viewmodel selected


    【解决方案1】:

    我确信它可以以这种方式工作,但是以另一种方式跟踪所选项目不是更容易吗?例如,绑定到包装实际集合的 ICollectionView(例如 ListCollectionView)允许使用内置的选择跟踪机制(ICollectionView 的 CurrentItem)。或者,您可以使用 ListBox 的 SelectedValue 和 SelectedValuePath。

    【讨论】:

    • 嗯...不是我现在要处理 IsSelected 的想法,而是您所说的 Alex 是对的。我非常关注带有 ViewModel 的 IsSelected。我现在做了这个: SelectedItem="{Binding SelectedDocumentViewModel,Mode=TwoWay}" 并在 DocumentViewModel:private bool CanDeleteDocument() { if(SelectedDocumentViewModel != null) return true;否则返回假;有效,但我想知道为什么 IsSelected 不起作用! ;-)
    • 我猜这是因为 ListBoxItem 的 IsSelected 属性是由 ListBox 在内部操作的,这会干扰绑定,但我可能会走投无路。不太确定。
    【解决方案2】:

    认为问题是删除命令不知道选择已更改。

    将 CanDeleteChanged 添加到中继命令并在 this.RaisePropertyChanged("IsSelected") 之后引发它。我以前在使用 Prism 应用时也遇到过类似的问题。

    编辑。事实上,你应该添加 CanDeleteChanged 并在其中放置一个断点,看看它是否在你期望的时候被调用。

    对不起,我的意思是删除中继命令上的 CanExecuteChanged 事件。您的代码应该在某处声明中继命令。为了这里的信息,它是

    公共类 RelayCommand : ICommand { #region 字段

    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
    

    }

    【讨论】:

    • 抱歉...但是如何向 RelayCommand 添加属性?请给我一个代码sn-p,我不知道代码应该是什么样子。
    • 另一个问题是虽然documentListBox是空的,但Button是启用的……我认为这个问题是由于删除按钮在DocumentViewModel中。由于没有 currentMeeting.DocumentList.Count > 0 我可以绑定到,因为我必须在加载整个会议时启用/禁用删除按钮。我应该将删除和其他按钮移到控制器上吗?但即便如此,我在控制器上也只有一个按钮命令,但在视图中我有 10 个会议,每个会议都有一个删除文档按钮。不工作...
    • 似乎我必须将按钮放在 DocumentListViewModel 中,就像他们在 WAF 中为 wpf 所做的那样!?
    • 好的,我现在制作了 DocumentListViewModel,它对绑定进行了多次试验和错误。但现在我已经全部工作了!如果 DocumentList 为空或未选择任何 Documents,则删除按钮被禁用 COOL,我应该开始写博客:P
    • 抱歉,最近几天没有检查 SO。对于 CanDeleteChanged,您应该查看 RelayCommand 的构造函数参数。
    猜你喜欢
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多