【问题标题】:WPF - ListBox ContentTemplate textbox MouseDown causing listbox item to NOT be selectedWPF - ListBox ContentTemplate 文本框 MouseDown 导致列表框项目未被选中
【发布时间】:2012-11-27 16:37:02
【问题描述】:

摘要:单击列表框项,DataTemplate 中的文本框获得焦点,但未选择列表框项。

我确定这与事件冒泡有关,但我在这里遗漏了一些东西。

我有列表框。每个 ListBoxItem 的 ContentTemplate 都分配给一个 DataTemplate,其中包含一个简单的文本框。

此文本框旨在显示为虚假的可编辑标签。

问题:单击文本框时,ListBox 的 selectedItem 没有被更新。文本框正在吞噬 mousedown 事件,并且永远不会通知列表框更新到新项目。

我觉得我在这里错过了一些愚蠢的东西。有任何想法吗?有没有办法强制事件冒泡到父 ListView?

从将文本框的背景设为 Null 到处理 previewmousedown 事件和设置 e.handled = false;,我已经尝试了所有方法。

数据模板:

<DataTemplate x:Key="ItemTempl">
            <TextBox Height="20" Width="200" Name="tbox" Text="{Binding WordText}" HorizontalAlignment="Stretch">
                <TextBox.Style>
                    <Style TargetType="TextBox">
                        <Setter Property="BorderThickness" Value="0"/>
                        <Setter Property="Background" Value="{x:Null}"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=IsFocused, ElementName=tbox}" Value="True">
                                <Setter Property="BorderThickness" Value="1"/>
                                <Setter Property="Background" Value="White"/>                                    
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
            </TextBox>
</DataTemplate>

列表视图:

<ListView HorizontalAlignment="Stretch" ItemsSource="{Binding Something.Words}" Name="MainListView" SelectedItem="{Binding CurrentItem, Mode=TwoWay}" BorderThickness="0" ItemContainerStyle="{StaticResource ContainerStyle}">
</ListView>

【问题讨论】:

  • 我在您的 ListView 中看不到 ItemTempl 的用法。你也没有解释ContainerStyle是什么。

标签: c# wpf events datatemplate listboxitem


【解决方案1】:

我通过创建自己的列表视图来解决 ListView 的这个特殊问题,该列表视图处理预览鼠标按下事件并选择项目,您可以根据自己的情况进行调整,最好在附加属性中执行此操作,这样您不必创建新类。

我基本上是在寻找鼠标向下的原始来源,即文本框,使用可视化树帮助程序一直跟随它的可视化树回到它所在的列表视图项并选择它。

 public class MyListView : ListView
    {
        protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
        {
            DependencyObject listViewItem = (DependencyObject)e.OriginalSource;
            while (listViewItem != null && !(listViewItem is ListViewItem))
                listViewItem = VisualTreeHelper.GetParent(listViewItem);

            SelectedItem = ((ListViewItem)listViewItem).Content;

            base.OnPreviewMouseDown(e);
        }
    }

编辑: 这是附加的属性版本。

public class ListViewExtras : DependencyObject
    {
        public static bool GetWillAlwaysSelect(DependencyObject obj)
        {
            return (bool)obj.GetValue(WillAlwaysSelectProperty);
        }

        public static void SetWillAlwaysSelect(DependencyObject obj, bool value)
        {
            obj.SetValue(WillAlwaysSelectProperty, value);
        }

        // Using a DependencyProperty as the backing store for WillAlwaysSelect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WillAlwaysSelectProperty =
            DependencyProperty.RegisterAttached("WillAlwaysSelect", typeof(bool), typeof(ListViewExtras), new PropertyMetadata(false, new PropertyChangedCallback((s, e) =>
            {
                ListView listView = s as ListView;
                if (listView != null)
                {
                    if ((bool)e.NewValue) listView.PreviewMouseDown += listView_PreviewMouseDown;
                    if (!(bool)e.NewValue && (bool)e.OldValue) listView.PreviewMouseDown -= listView_PreviewMouseDown;
                }
            })));

        static void listView_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ListView listView = sender as ListView;
            if (listView != null)
            {
                DependencyObject listViewItem = (DependencyObject)e.OriginalSource;
                while (listViewItem != null && !(listViewItem is ListViewItem))
                    listViewItem = VisualTreeHelper.GetParent(listViewItem);
                listView.SelectedItem = ((ListViewItem)listViewItem).Content;
            }
        }
    }

并与它一起使用

<ListView HorizontalContentAlignment="Stretch" local:ListViewExtras.WillAlwaysSelect="True">

【讨论】:

  • 出色的解决方案。万分感谢。像魅力一样工作
【解决方案2】:

我将事件处理程序更改为更通用,支持使用 ContainerFromElement 和 ItemContainerGenerator.IndexFromContainer 方法的任何选择器。

    private static void OnPreviewListBoxMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        var listBox = sender as Selector;
        if (listBox != null)
        {
            DependencyObject mouseItem = e.OriginalSource as DependencyObject;
            if (mouseItem != null)
            {
                // Get the container based on the element
                var container = listBox.ContainerFromElement(mouseItem);
                if (container != null)
                {
                    var index = listBox.ItemContainerGenerator.IndexFromContainer(container);
                    Debug.Assert(index >= 0);
                    listBox.SelectedIndex = index;
                }
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 2010-12-21
    • 2018-12-09
    • 1970-01-01
    • 2015-10-20
    相关资源
    最近更新 更多