我有一个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>
我通过将UserControl内部的TextBlock文本绑定到另一个类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还是很陌生,希望对使用UserControl并将ItemSource设置为没有ListViewItems的项目时如何保留IsMouseOver属性提供帮助。
答案 0 :(得分:1)
这是做您想做的最简单的方法。当用集合中的项目填充ListView时,它会创建自己的ListViewItems。您无需在每个ListViewItems内创建另一个ListViewItem,而不必在您自己的列表内创建第三个ListViewItem。
我将省去UserControl并将该XAML直接放在模板中。这样做的原因是我们希望单击处理程序位于MainWindow.xaml.cs中,并可以在其中与主视图模型进行交互。我们可以通过两种不同的方式很容易地使它与UserControl一起使用,但我会尽量简化这一过程。理想情况下,您应该使用Command
,但这是一种特殊情况,其中MVVM中的少量杂质不会破坏您。对于项UI像一个文本块和一个按钮一样简单的情况,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>();
}