这几天一直与ListBox打交道,对ListBox的了解也加深了一层,这篇文章把相关的思路写下来,为了简化起见,省略了一些无关重要的东西
首先声明数据源对象,这里以一个简单的类为例
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class People : ObservableCollection<Person>
{
public List<Person> Detailes { get; set; }
public People()
{
Detailes = new List<Person>
{
new Person{FirstName="David",LastName="White"},
new Person{FirstName="Jim",LastName="Green"},
new Person{FirstName="Tom",LastName="Polly"}
};
}
}
数据源已经建立好了,现在将其绑定到ListBox中,这里需要横向绑定,SDK中有横向绑定的实现,这里就不再进行细说,按照需求,当鼠标移到FirstName时提示关于LastName的信息,才开始做的时候总是无法显示提示信息,然后在网上找到了原因:附加属性ToolTipService.ToolTip并没有继承上层元素的DataContext
原因找到了,解决思路就清晰了,先声明一个值转换器
public class MyConvert : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
var str = value.ToString();
TextBlock tb = new TextBlock();
tb.Text = str;
return tb;
}
return null;
}
...
}
将相关的类声明为资源
<loacls:People x:Key="people"></loacls:People>
<loacls:MyConvert x:Key="convert"></loacls:MyConvert>
Xaml代码:
<Grid DataContext="{StaticResource people}" >
<ListBox ItemsSource="{Binding Detailes}"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding FirstName}" ToolTipService.Placement="Mouse"
ToolTipService.ToolTip="{Binding LastName,Converter={StaticResource convert}}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
这样就能够最终显示提示信息了,
现在我需要将提示信息随鼠标的移动而移动,网上有实现的方法,不过我这里首先要需要解决怎样获取DataTemplate内的控件
<TextBlock x:Name="myTxt" MouseMove="TextBlock_MouseMove" FontFamily="Arial" Foreground="#333333" FontSize="18" Text="{Binding FirstName}">
<ToolTipService.ToolTip>
<ToolTip x:Name="tip" Placement="Mouse">
<Binding Path="LastName" Converter="{StaticResource convert}"></Binding>
</ToolTip>
</ToolTipService.ToolTip>
</TextBlock>
DataTemplate进行了一些改动,那么我需要先获取TextBlock,再获取其中的ToolTip,这个部分参考了园里这篇文章,当鼠标在TextBlock移动时,就进行下面的处理:
private void TextBlock_MouseMove(object sender, MouseEventArgs e)
{
double x;
Random random = new Random();
x = e.GetPosition(null).X;
ListBoxItem _selectedItem;
if (this.listBox1.SelectedItem != null)
{
_selectedItem = (ListBoxItem)(this.listBox1.ItemContainerGenerator.ContainerFromItem(this.listBox1.SelectedItem));
}
else
{
_selectedItem = (ListBoxItem)(this.listBox1.ItemContainerGenerator.ContainerFromItem(this.listBox1.Items[0]));
}
TextBlock myTxt = FindFirstVisualChild<TextBlock>(_selectedItem, "myTxt");
ToolTip tip = myTxt.FindName("tip") as ToolTip;
if (tip != null)
{
if (x > 5)
{
tip.HorizontalOffset = random.Next(1, 3);
}
else
{
tip.HorizontalOffset = x;
}
}
}
获取可视化的代码也贴出来:
public T FindFirstVisualChild<T>(DependencyObject obj,string childName) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T && child.GetValue(NameProperty).ToString()==childName)
{
return (T)child;
}
else
{
T childOfChild = FindFirstVisualChild<T>(child,childName);
if (childOfChild != null)
{
return childOfChild;
}
}
}
return null;
}完成以后,就实现选择ListBox的Item时,提示信息就会跟随鼠标的移动而移动了。其实利用上面的方法,也可以动态的改变listboxItem的背景色
_selectedItem.Background = new SolidColorBrush(Colors.Orange);
上面所讲用到不少的知识点,希望对你有所帮助,不过上面有个地方我总是无法实现,即如DataGrid那样,将ListBoxItem的背景色进行交替变换,我模仿MSDN上改变 ListView 中各行的背景色进行修改,但是没能实现,只好以后如果解决了再贴出来,如果有朋友实现过这个功能,也请不吝赐教!
代码下载:ListBoxExample.rar