WPF:ListView&编辑ListViewItem

时间:2013-01-29 17:11:15

标签: c# wpf listview

enter image description here

我希望能够选择一个项目,然后编辑其标签:

  • 选择项目
  • 项目突出显示
  • 点击它的标签
  • Label的TextBlock替换为TextBox
  • 修改标签
  • 一次只能编辑一个项目

结束编辑:

  1. 点击项目图标:
    • TextBox将替换为TextBlock
    • 项目仍然突出显示
  2. 点击了另一个项目:
    • TextBox将替换为TextBlock
    • 未选择已修改的项目
    • 选中并突出显示已点击的项目
  3. 点击窗口的任何其他区域:
    • TextBox将替换为TextBlock
    • 编辑的项目仍然突出显示
  4. 行为应该与Windows资源管理器中的行为非常相似。

    我设法完成了大部分要求。我仍然得到随机结果。例如,在第一次启动时,我可以直接点击标签进行编辑。项目本身不会突出显示。这只在开始时发生。

    同样使用滚动条不会将焦点从列表项中移开。这允许同时编辑多个项目。

    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>
    

    代码

    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

    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

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

    感谢阅读长篇文章。

    我在StackOverflow中搜索并阅读了很多答案,但这些答案对我来说都不是很好。

    例如:

2 个答案:

答案 0 :(得分:0)

您可能希望捕获listview上的scrollevent并显式删除对元素的焦点。

    ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(mTreeView);
    scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer.....

并在处理程序中删除焦点。

查看此stackoverflow页面,将焦点从元素移开 WPF: How to programmatically remove focus from a TextBox

答案 1 :(得分:0)

也许最好在不同状态下切换IsReadonly属性?然后,您将不再需要切换可见性。此外,在这种情况下更换模板更好。