ViewModel 的 IsSelected 属性绑定到 ListBox,只有第一个项目选择有效?
我有一个绑定到 DataGrid 的 MeetingViewModelList。 每个 MeetingViewModel 都有一个 DocumentViewModelList 绑定到 DataGrid 的 DataGridTemplateColumn 内的 ListBox。
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.
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我确信它可以以这种方式工作,但是以另一种方式跟踪所选项目不是更容易吗?例如,绑定到包装实际集合的 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.
我认为问题是删除命令不知道选择已更改。
将 CanDeleteChanged 添加到中继命令并在 this.RaisePropertyChanged("IsSelected") 之后引发它。我之前在使用 Prism 应用程序时也遇到过类似的问题。
编辑。事实上,您应该添加 CanDeleteChanged 并在其中放置一个断点,看看它是否在您期望的时候被调用。
抱歉,我的意思是删除中继命令上的 CanExecuteChanged 事件。您的代码应该在某处声明中继命令。为了此处提供信息,它是
公共类 RelayCommand : ICommand
{
#region 字段
}
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
}