Получение 'IsMouseOver' для работы с ListView, когда ItemsSource установлен в список - PullRequest
0 голосов
/ 27 июня 2019

У меня есть проект WPF, в котором я создал UserControl с целью создания пользовательского ListViewItem, который включает в себя кнопку закрытия внутри.Вот код для этого:

<ListViewItem x:Name="lviTab" Height="36" Background="#232323" 
MouseUp="LviTab_MouseUp" MouseEnter="LviTab_MouseEnter">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding TabText}" FontSize="15" />
        <ListViewItem x:Name="lviTabClose" Margin="5, 0, 0, 0" 
Padding="0, 0, 0, 0" MouseUp="LviTabClose_MouseUp">
            <materialDesign:PackIcon Kind="Close" Foreground="White" 
VerticalAlignment="Center"

HorizontalAlignment="Center" Width="20" Height="20" />
        </ListViewItem>
    </StackPanel>
</ListViewItem>

Я корректирую текст внутри каждого элемента, привязывая текст TextBlock внутри UserControl к другому классу TabData.cs

public class TabData : UIElement
{
    public TabData() : base()
    {
    }

    public string TabText { get; set; }
}

В моем ListView я установил DataTemplate в свой UserControl.Я установил ListView ItemSource для списка объектов TabData.

tabs = new List<TabData>()
        {
            new TabData{TabText = "Tab 1"},
            new TabData{TabText = "Tab 2"},
            new TabData{TabText = "Tab 3"},
            new TabData{TabText = "Tab 4"},
            new TabData{TabText = "Tab 5"}
        };

        lvTabs.ItemsSource = tabs;

При наведении мыши на ListViewItem мне нужно, чтобы IsMouseOver был true.Я пытался наследовать UIElement для TabData, но это не сработало.Я довольно новичок в WPF, я был бы признателен за любую помощь в выяснении, как я могу сохранить свойство IsMouseOver при использовании UserControl и установке ItemSource для элементов, которые не являются ListViewItems.

1 Ответ

1 голос
/ 27 июня 2019

Вот самый простой способ сделать то, что вы пытаетесь сделать. Когда вы заполняете ListView элементами из коллекции, он создает свои собственные ListViewItems. Вам не нужно создавать другой ListViewItem внутри каждого из его ListViewItems, а тем более третий внутри вашего собственного.

Я собираюсь обойтись без UserControl и поместить этот XAML прямо в шаблон. Причина в том, что мы хотим, чтобы обработчик кликов находился в MainWindow.xaml.cs, где он может взаимодействовать с основной моделью представления. Мы могли бы довольно легко заставить это работать с UserControl несколькими различными способами, но я держу это настолько простым, насколько я могу. В идеале вы бы использовали Command для этого, но это один конкретный случай, когда небольшая примесь в вашем MVVM не испортит вас. А для случая, когда пользовательский интерфейс элемента так же прост, как один текстовый блок и одна кнопка, UserControl - это больше, чем вам нужно.

Сначала MainWindow.xaml

<Window.Resources>
    <DataTemplate x:Key="TabListViewItemTemplate">
        <DockPanel LastChildFill="False">
            <TextBlock Text="{Binding TabText}" DockPanel.Dock="Left" />
            <Button x:Name="TabCloseButton" Click="TabCloseButton_Click" DockPanel.Dock="Right" >
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <materialDesign:PackIcon 
                            Kind="Close" Foreground="White" 
                            VerticalAlignment="Center" HorizontalAlignment="Center" 
                            Width="20" Height="20" />
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </DockPanel>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListView
        ItemsSource="{Binding TabItems}"
        ItemTemplate="{StaticResource TabListViewItemTemplate}"
        HorizontalContentAlignment="Stretch"
        />
</Grid>

MainWindow.xaml.cs

public MainWindow()
{
    InitializeComponent();

    DataContext = new MainViewModel
    {
        TabItems = {
            new TabData { TabText = "Fred" },
            new TabData { TabText = "Ginger" },
            new TabData { TabText = "Herman" },
        }
    };
}

private void TabCloseButton_Click(object sender, RoutedEventArgs e)
{
    if ((sender as FrameworkElement).DataContext is TabData tabData)
    {
        MessageBox.Show($"TabCloseButton_Click() {tabData.TabText}");
    }
}

Класс TabData. Не наследуй от UIElement. Это не элемент в пользовательском интерфейсе, это просто класс C #. Если вы собираетесь позволить пользователю редактировать TabText, вы сделаете его моделью представления, которая реализует INotifyPropertyChanged.

    public class TabData
    {
        public string TabText { get; set; }
    }

Основной вид модели. Ничто из того, что мы делаем здесь, на самом деле не требует INotifyPropertyChanged для любого из ваших классов, но вам это понадобится, если вы превратите это во что-нибудь полезное, поэтому мы включим его.

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}

public class MainViewModel : ViewModelBase
{
    public ObservableCollection<TabData> TabItems { get; } = new ObservableCollection<TabData>();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...