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));
}
}
}