C# 滚动列表框时防止选择

C# 滚动列表框时防止选择,c#,wpf,listbox,touch,wpf-4.5,C#,Wpf,Listbox,Touch,Wpf 4.5,我有一个将鼠标事件转换为触摸事件的应用程序,因此我可以使用惯性滚动和其他触摸功能。该代码位于此处选择的答案中: 我的列表框出现的问题是,当我轻弹滚动时,它会选择项目。正常情况下,触摸设备在滚动时不会选择列表框项。我错过了什么 以下是我正在使用的xaml: <Window x:Class="ScrollingTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x

我有一个将鼠标事件转换为触摸事件的应用程序,因此我可以使用惯性滚动和其他触摸功能。该代码位于此处选择的答案中:

我的
列表框出现的问题是,当我轻弹滚动时,它会选择项目。正常情况下,触摸设备在滚动时不会选择
列表框
项。我错过了什么

以下是我正在使用的xaml:

<Window x:Class="ScrollingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="600" Width="525">
    <Grid>
        <ListBox x:Name="testListBox"               
                 VirtualizingPanel.ScrollUnit="Pixel" 
                 SelectionMode="Single">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border CornerRadius="3" Height="60" Width="480" Background="LightGray" Margin="1">
                        <Label Content="{Binding}"/>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>               
        </ListBox>
    </Grid>
</Window>

代码隐藏:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MouseTouchDevice.RegisterEvents(this);

        for (int i = 0; i < 300; i++)
        {
            testListBox.Items.Add("test " + i.ToString());
        }
    }       
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
鼠标触摸设备。注册表事件(此);
对于(int i=0;i<300;i++)
{
testListBox.Items.Add(“test”+i.ToString());
}
}       
}

我找到的唯一方法是使用
DataTrigger
ListBoxItem
Focusable
属性设置为false。在我的例子中,当用户flick滚动时,我将属性
IsScrolling
设置为false,当kenitic移动停止时,这将停止选择行为,同时快速浏览列表

此解决方案可能在您的场景中不起作用,但这里有一个工作示例,您可以适应为自己工作

Xaml:


代码:

public分部类主窗口:窗口,INotifyPropertyChanged
{
私有ObservableCollection myVar=新ObservableCollection();
私有日期时间\u lastScroll;
公共主窗口()
{
初始化组件();
鼠标触摸设备。注册表事件(此);
对于(int i=0;i<1000;i++)
{
列表。添加(“StackOverflow”+i);
}
}
公共可观测收集列表
{
获取{return myVar;}
设置{myVar=value;}
}
公共场所
{
获取{return!(DateTime.Now>\u lastcoll.addmillizes(100));}
}
私有无效列表\u ScrollChanged(对象发送者,ScrollChangedEventArgs e)
{
_lastcoll=DateTime.Now;
ThreadPool.QueueUserWorkItem((o)=>
{
睡眠(100);
通知财产变更(“IsCrolling”);
});
}
公共事件属性更改事件处理程序属性更改;
私有void NotifyPropertyChanged(字符串属性)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(property));
}
}
}

我认为这可以通过使用装饰器来实现

MSDN样品

装饰很简单;它在这里可以很好地使用。 参考下面的链接,如果不喜欢覆盖,可以将装饰层背景设置为透明


我知道这是一个老问题,但我有一个确定的解决方案。 设置
ScrollViewer.PanningMode
属性可启用触摸滚动,从而防止在
鼠标上进行选择。例如,对于一个简单的滚动场景,只需设置PanningMode=“VerticalOnly”
,就可以了


希望我帮助了某人

我认为这是一个聪明的解决方案,但它有一些问题。第一种方法是,如果项模板包含按钮,则将容器样式设置为“不可聚焦”仍将允许按钮单击并触发命令。另一个问题是它不太可重用,我有大约35个视图模型,需要实现这种行为MVVM风格,这确实很有效。我已经更新了答案,以便在
ItemTemplates
上工作。在这种情况下,我们将
ishitestvisible
设置为false,而不是
Focusable
,现在我们只需要找到一种好的方法来通知
IsScrolling
,我将有一个剧本,并尝试找到一个通用的方法来实现这一点。我已经用一个非常有效的示例更新了我的答案,它可能不是最吸引人的解决方案,但我认为它适用于您的情况(适用于我的:))这不起作用,项目选择仍然会出现在第一个卷轴上。您希望如何选择项目,它如何知道您想要滚动或选择,也许您需要一个“触摸并按住”选择或另一个手势。这个回答太笼统了。@Robert感谢您的反馈,更新了更多详细信息。希望对你有帮助。
<Window x:Class="WpfApplication13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Name="UI">
    <Grid DataContext="{Binding ElementName=UI}">
        <ListBox Margin="0,32,0,0" ItemsSource="{Binding List}" ScrollViewer.ScrollChanged="List_ScrollChanged">
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsScrolling, ElementName=UI}" Value="True">
                            <Setter Property="IsHitTestVisible" Value="False"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>
public partial class MainWindow : Window, INotifyPropertyChanged
{

    private ObservableCollection<string> myVar = new ObservableCollection<string>();
    private DateTime _lastScroll;

    public MainWindow()
    {
        InitializeComponent();
        MouseTouchDevice.RegisterEvents(this);
        for (int i = 0; i < 1000; i++)
        {
            List.Add("StackOverflow " + i);
        }
    }

    public ObservableCollection<string> List
    {
        get { return myVar; }
        set { myVar = value; }
    }

    public bool IsScrolling
    {
        get { return !(DateTime.Now > _lastScroll.AddMilliseconds(100)); }
    }

    private void List_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        _lastScroll = DateTime.Now;
        ThreadPool.QueueUserWorkItem((o) =>
        {
            Thread.Sleep(100);
            NotifyPropertyChanged("IsScrolling");
        });
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}