突出显示列表框中的多个项目

时间:2013-07-02 16:12:23

标签: c# wpf mvvm

有没有办法实现办公室撤销下拉(图像波纹管)? 我的意思是,当用户将鼠标悬停在除第一项以外的项目上时,我想突出显示上一项 我尝试了一些来自FluentRibbon的控件,但到目前为止没有运气..

enter image description here

2 个答案:

答案 0 :(得分:2)

在大多数情况下,设计这样的控件是在Blend中完成的。但是,如果您不知道如何使用Blend,您仍然可以通过XAML和代码隐藏获得类似的结果,但您必须做更多的工作。

我们首先创建一个名为CustomListBoxItem的类,它继承自ListBoxItem。然后,我们定义一个依赖项属性,用于突出显示列表框中的项目:

public class CustomListBoxItem : ListBoxItem
{
    public static readonly DependencyProperty IsVirtuallySelectedProperty =
       DependencyProperty.Register("IsVirtuallySelected", typeof(bool), 
                                   typeof(CustomListBoxItem),
                                   new PropertyMetadata(false));

    public CustomListBoxItem() : base()
    { }

    public bool IsVirtuallySelected
    {
        get { return (bool)GetValue(IsVirtuallySelectedProperty); }
        set { SetValue(IsVirtuallySelectedProperty, value); }
    }
}

然后我们添加一个列表框并在XAML中为它定义一个样式:

<ListBox Name="listBox" MouseMove="listBox_MouseMove" SelectionChanged="listBox_SelectionChanged">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type local:CustomListBoxItem}">
                <Style.Triggers>
                    <Trigger Property="IsVirtuallySelected" Value="true">
                        <Setter Property="Background" Value="SkyBlue"/>
                    </Trigger>
                    <Trigger Property="IsVirtuallySelected" Value="false">
                        <Setter Property="Background" Value="White"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ListBox.ItemContainerStyle>
</ListBox>

其中local是定义CustomListBoxItem的命名空间。这就是我们XAML部分所需要的,真正的魔力发生在后面的代码中。

listBox_MouseMove事件处理程序如下所示:

private void listBox_MouseMove(object sender, MouseEventArgs e)
    {
        bool itemFound = false;

        for (int i = 0; i < listBox.Items.Count; i++)
        {
            var currentItem = listBox.ItemContainerGenerator.ContainerFromIndex(i) as CustomListBoxItem;

            if (currentItem == null) 
                continue;

            // Check whether the cursor is on an item or not.
            if (IsMouseOverItem(currentItem, e.GetPosition((IInputElement)currentItem)))
            {
                // Unselect all items before selecting the new group
                listBox.Items.Cast<CustomListBoxItem>().ToList().ForEach(x => x.IsVirtuallySelected = false);

                // Select the current item and the ones above it
                for (int j = 0; j <= listBox.Items.IndexOf(currentItem); j++)
                {
                    ((CustomListBoxItem)listBox.Items[j]).IsVirtuallySelected = true; 
                }

                itemFound = true;
                break;
            }
        }

        // If the item wasn't found for the mouse point, it means the pointer is not over any item, so unselect all.
        if (!itemFound)
        {
            listBox.Items.Cast<CustomListBoxItem>().ToList().ForEach(x => x.IsVirtuallySelected = false);
        }
    }

用于确定光标是否在项目上的IsMouseOverItem辅助方法定义如下:

 private bool IsMouseOverItem(Visual item, Point mouseOverPoint)
    {
        Rect currentDescendantBounds = VisualTreeHelper.GetDescendantBounds(item);
        return currentDescendantBounds.Contains(mouseOverPoint);
    }

最后是listBox_SelectedChanged事件处理程序,它充当ListBox的单击处理程序:

 private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // Get all the virtually selected items
        List<CustomListBoxItem> selectedItems =
            listBox.Items.Cast<CustomListBoxItem>().Where(x => x.IsVirtuallySelected).ToList();

        if (selectedItems == null || !selectedItems.Any())
            return;

        // Do something with the selected items
        DoCoolStuffWithSelectedItems();

        // Unselsect all.
        listBox.Items.Cast<CustomListBoxItem>().ToList().ForEach(x => x.IsVirtuallySelected = false);
        listBox.UnselectAll();
    }

繁荣,我们已经完成了。我们现在可以在类构造函数中向ListBox添加一些项:

 public MainWindow()
    {
        InitializeComponent();


        listBox.Items.Add(new CustomListBoxItem { Content = "hello world!" });
        listBox.Items.Add(new CustomListBoxItem { Content = "wpf is cool" });
        listBox.Items.Add(new CustomListBoxItem { Content = "today is tuesday..." });
        listBox.Items.Add(new CustomListBoxItem { Content = "I like coffee" });
    }

请注意,我使用随机颜色作为XAML中的高亮颜色。随意改变它并尝试一下。

答案 1 :(得分:1)

猜猜你需要这样的东西:

<ControlTemplate TargetType="ListBoxItem">
    <TextBlock Text="{Binding LastOperation}">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Style.Triggers>
                    <DataTrigger>
                        <DataTrigger.Binding>
                            <MultiBinding>
                                <Binding Path="MouseOverIndex"/>
                                <Binding Path="CurrentIndex"/>
                            </MultiBinding>
                        </DataTrigger.Binding>
                        <Setter Property="Foreground" Value="Gold"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</ControlTemplate>