WPF:ListView 和编辑 ListViewItem
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14588336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF: ListView & Editing ListViewItem
提问by J Pollack


I want to be able to select an item and then edit its label:
我希望能够选择一个项目,然后编辑它的标签:
- Select an item
- Item is highlighted
- Click on it's label
- Label's TextBlock is replaced with TextBox
- Modify the label
- Only one item can be edited at a time
- 选择一个项目
- 项目突出显示
- 点击它的标签
- Label 的 TextBlock 替换为 TextBox
- 修改标签
- 一次只能编辑一项
End the editing:
结束编辑:
- Click onto item's icon:
- TextBox is replaced back with TextBlock
- Item remains highlighted
- Another item is clicked:
- TextBox is replaced back with TextBlock
- Edited item is unselected
- Clicked item is selected and highlighted
- Any other area of the window is clicked:
- TextBox is replaced back with TextBlock
- Edited item remains highlighted
- 单击项目的图标:
- TextBox 被替换回 TextBlock
- 项目保持突出显示
- 单击另一个项目:
- TextBox 被替换回 TextBlock
- 已取消选择已编辑的项目
- 单击的项目被选中并突出显示
- 单击窗口的任何其他区域:
- TextBox 被替换回 TextBlock
- 已编辑的项目保持突出显示
The behaviour should be pretty much as in Windows Explorer.
该行为应该与 Windows 资源管理器中的非常相似。
I managed to accomplish most of the requirements. Still I get random results. For example on first launch I could click straight onto label to edit it. The item itself remains not highlighted. This occurs only at start.
我设法完成了大部分要求。我仍然得到随机结果。例如,在第一次启动时,我可以直接单击标签进行编辑。该项目本身仍然没有突出显示。这仅在开始时发生。
Also using the scroll-bar does not take focus off the list item. This allows to edit multiple items at the same time.
同样使用滚动条不会将焦点从列表项上移开。这允许同时编辑多个项目。
XAML
XAML
<Window x:Class="WPFComponents.DailyImages"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Model="clr-namespace:WPFComponents.Model"
Title="Media Items" Height="300" Width="300">
<ListView x:Name="_mediaItemList" ItemsSource="{Binding MediaItems}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionMode="Multiple"
MouseLeftButtonDown="OnClickMediaList" IsSynchronizedWithCurrentItem="True">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate DataType="Model:MediaItem">
<Grid Width="80" Margin="4">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Image HorizontalAlignment="Center" Stretch="Uniform" Source="{Binding Path=IconPath}" Width="70" />
<StackPanel Grid.Row="2">
<TextBlock Text="{Binding Path=Date}" TextWrapping="Wrap" />
<TextBlock x:Name="_labelTextBlock" Text="{Binding Path=Label}" TextWrapping="Wrap"
PreviewMouseLeftButtonDown="OnClickLabelBlock">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible" />
</Style>
</TextBlock.Style>
</TextBlock>
<TextBox x:Name="_labelTextBox" Text="{Binding Path=Label}" Visibility="Collapsed"
TextWrapping="WrapWithOverflow" TextAlignment="Center"
LostFocus="OnTextLostFocus">
</TextBox>
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
<Setter TargetName="_labelTextBlock" Property="Visibility" Value="Collapsed" />
<Setter TargetName="_labelTextBox" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Code
代码
public partial class DailyImages
{
public DailyImages()
{
InitializeComponent();
ViewModel.DailyImages dailyImages = new ViewModel.DailyImages();
_mediaItemList.DataContext = dailyImages;
}
private void OnClickLabelBlock(object sender, MouseButtonEventArgs e)
{
TextBlock notes = sender as TextBlock;
if (notes == null) return;
MediaItem selectedMedia = notes.DataContext as MediaItem;
if (selectedMedia == null) return;
// Multiple items might be selected
// Clear all selected items
_mediaItemList.SelectedItems.Clear();
// Reselect
selectedMedia.IsSelected = true;
selectedMedia.IsEditing = true;
Mouse.Capture(this, CaptureMode.SubTree);
}
private void OnTextLostFocus(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
MediaItem mediaItem = textBox.DataContext as MediaItem;
if (mediaItem == null)
return;
// End the label editing
mediaItem.IsEditing = false;
ReleaseMouseCapture();
}
private void OnClickMediaList(object sender, MouseButtonEventArgs e)
{
// End the label editing
foreach (MediaItem mediaItem in _mediaItemList.Items)
mediaItem.IsEditing = false;
ReleaseMouseCapture();
}
}
MediaItem.cs
媒体项.cs
public class MediaItem : INotifyPropertyChanged
{
private bool _isEditing;
private bool _isSelected;
private string _label;
public MediaItem()
{
IsEditing = false;
_isSelected = false;
}
public bool IsEditing
{
get { return _isEditing; }
set
{
if (_isEditing == value) return;
_isEditing = value;
OnPropertyChanged("IsEditing");
}
}
public string Label
{
get { return _label; }
set
{
_label = value;
OnPropertyChanged("Label");
}
}
public DateTime Date { get; set; }
public string IconPath { get; set; }
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
DailyImages.cs
DailyImages.cs
public class DailyImages
{
private ObservableCollection<MediaItem> _mediaItems;
public DailyImages()
{
_mediaItems = new ObservableCollection<MediaItem>();
_mediaItems.Add(new MediaItem {Label = "Image 1", IconPath = "Resources/Icon1.png"});
_mediaItems.Add(new MediaItem {Label = "Image 2", IconPath = "Resources/Icon2.png"});
_mediaItems.Add(new MediaItem {Label = "Image 3", IconPath = "Resources/Icon3.png"});
_mediaItems.Add(new MediaItem {Label = "Image 4", IconPath = "Resources/Icon4.png"});
_mediaItems.Add(new MediaItem {Label = "Image 5", IconPath = "Resources/Icon5.jpg"});
_mediaItems.Add(new MediaItem {Label = "Image 6", IconPath = "Resources/Icon6.png"});
_mediaItems.Add(new MediaItem {Label = "Image 7", IconPath = "Resources/Icon7.png"});
_mediaItems.Add(new MediaItem {Label = "Image 8", IconPath = "Resources/Icon8.png"});
_mediaItems.Add(new MediaItem {Label = "Image 9", IconPath = "Resources/Icon9.png"});
}
public ObservableCollection<MediaItem> MediaItems
{
get { return _mediaItems; }
set { _mediaItems = value; }
}
}
Thanks for reading the long post.
感谢您阅读长篇文章。
I have searched and read many answers here in StackOverflow but none of them were great for me.
我在 StackOverflow 中搜索并阅读了许多答案,但没有一个对我来说很好。
For example:
例如:
回答by TYY
You may want to capture the scrollevent on the listview and explicitly remove the focus on the element.
您可能希望在列表视图上捕获滚动事件并显式移除元素上的焦点。
ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(mTreeView);
scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer.....
and within the handler remove focus.
并在处理程序中移除焦点。
Look at this stackoverflow page for moving focus away from elements WPF: How to programmatically remove focus from a TextBox
查看此 stackoverflow 页面以将焦点从元素上移开 WPF:How to programmatically remove focus from a TextBox
回答by Lonli-Lokli
Maybe it's better to switch IsReadonly property in different states? Then you will no longer need to switch visibility. Also, it's better to replace templates in this case.
也许在不同状态下切换 IsReadonly 属性会更好?然后您将不再需要切换可见性。此外,在这种情况下最好更换模板。

