ViewModel 的 IsSelected 属性绑定到 ListBox,只有第一个项目选择有效?

发布于 2024-09-18 14:49:00 字数 10117 浏览 2 评论 0原文

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

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

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

DocumentViewModel 中的删除文档按钮会在其 CanExecute 方法中检查以下内容:

private bool CanDeleteDocument()
        {
            return _isSelected;
        }

当我选择 ListBox 中的 FIRST 项时,删除按钮已启用。 当我选择列表框中的第二个、第三个等项目时,“删除”按钮始终处于禁用状态。

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

我刚刚尝试仅使用 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");
        }
    }       
}

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

偏闹i 2024-09-25 14:49:00

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

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.

捂风挽笑 2024-09-25 14:49:00

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

将 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

}

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

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文