首先出现Expander崩溃而没有回馈空间的问题
基于边界,看起来ListView并没有缩小,而是Expander没有缩小
以下代码修复了收缩问题
来自ListBox control does not shrink
这会失去虚拟化,但我很好,因为这是我需要显示的数据。
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
但后来出现了一个新问题
如果你打开任何两个级别的Expander并尝试点击复选框,它会经常跳转,有时跳得太多,以至于点击错过了复选框。
一直滚动到底部,因此复选框不在底部(下方有一些扩展器)
然后点击它会跳,很可能甚至错过了这个项目
我可以多次尝试检查或取消选中最后一行
很确定这是因为点击被处理两次并且事物之间移动。
那么如何解决这两个问题呢?
1.收缩/收回空间?
2.复选框不跳?
通过调度程序,UpdateLayout(),InvalidateVisual()和Height = Double.NaN尝试刷新。
StackPanel不是问题,因为我可以删除它并仅使用Exp1但仍有问题
在使用SelectedItem双击之前有一个类似的问题,我能够通过吃第二次点击修复,但该修复在这里不起作用。 MissClick
尝试TreeView但我没有在每个级别显示相同的信息,因此它不起作用
但我对另一种方法持开放态度
两级层次结构,只需要在第二级复选框。
很抱歉很多代码,但这是一个重现问题的完整程序 Exp1与Exp2完全相同,并不是真正需要重现问题,但如果有人建议使用备用解决方案,则反映真实程序。
<Window x:Class="ListViewJump.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="165"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" Grid.Column="0"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<StackPanel>
<Expander IsExpanded="False" Header="Exp1" BorderThickness="2" BorderBrush="Green">
<ListView ItemsSource="{Binding Path=List1}"
HorizontalAlignment="Left" BorderThickness="2" BorderBrush="Orange">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate >
<DataTemplate>
<Expander Header="{Binding Path=DispName}">
<ListView ItemsSource="{Binding Path=Rows}"
HorizontalAlignment="Left" BorderThickness="2" BorderBrush="Purple">
<ListView.ItemTemplate >
<DataTemplate>
<CheckBox Width="125" IsChecked="{Binding Path=On}">
<TextBlock Text="{Binding Path=StrValue}" TextWrapping="Wrap"/>
</CheckBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Expander>
<Expander IsExpanded="False" Header="Exp2" BorderThickness="2" BorderBrush="Green">
<ListView ItemsSource="{Binding Path=List2}"
HorizontalAlignment="Left" BorderThickness="2" BorderBrush="Orange">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate >
<DataTemplate>
<Expander Header="{Binding Path=DispName}">
<ListView ItemsSource="{Binding Path=Rows}"
HorizontalAlignment="Left" BorderThickness="2" BorderBrush="Purple">
<ListView.ItemTemplate >
<DataTemplate>
<CheckBox Width="125" IsChecked="{Binding Path=On}">
<TextBlock Text="{Binding Path=StrValue}" TextWrapping="Wrap"/>
</CheckBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Expander>
</StackPanel>
</ScrollViewer>
</Grid>
</Window>
namespace ListViewJump
{
public partial class MainWindow : Window
{
private List<ListItem> list1 = new List<ListItem>();
private List<ListItem> list2 = new List<ListItem>();
public MainWindow()
{
this.DataContext = this;
for (int i = 1; i < 10; i++)
{
List<ListItemRow> lr1 = new List<ListItemRow>();
List<ListItemRow> lr2 = new List<ListItemRow>();
for (int j = 1; j < 100; j++)
{
lr1.Add(new ListItemRow("Row Row Row Row Row Row" + j.ToString()));
lr2.Add(new ListItemRow("Rwo Rwo Rwo Rwo Rwo Rwo" + j.ToString()));
}
list1.Add(new ListItem("one " + i.ToString(), lr1));
list2.Add(new ListItem("two " + i.ToString(), lr2));
}
InitializeComponent();
}
public List<ListItem> List1 { get { return list1; } }
public List<ListItem> List2 { get { return list2; } }
}
public class ListItem
{
private string dispName;
private List<ListItemRow> rows;
public string DispName { get { return dispName; } }
public List<ListItemRow> Rows { get { return rows; } }
public ListItem(String DispName, List<ListItemRow> Rows) { dispName = DispName; rows = Rows; }
}
public class ListItemRow
{
private string strValue;
private bool on = false;
public string StrValue { get { return strValue; } }
public bool On
{
get { return on; }
set { on = value; }
}
public ListItemRow(String StrValue) { strValue = StrValue; }
}
}
我认为这里有两个错误
控制不缩小,点击两次处理。
我收缩会增加开销,但仍然为什么不是一个选项。
答案 0 :(得分:2)
我花了很多时间玩你的例子,但我最终意识到这种行为的根本原因是什么,以及要去寻找什么。
我认为您遇到的问题是CheckBox
点击后获得焦点,并引发RequestBringIntoView
事件,这实际上会导致ScrollViewer
启动包含您的控件CheckBox
进入“正确”的地方。这个答案解释了这些机制:Stop WPF ScrollViewer automatically scrolling to perceived content。
如果在您点击CheckBox
时发生滚动,它会从您的光标下移出,然后您可以取消点击鼠标(您可以通过在问题发生时按住鼠标来证明这一点,并且随后将鼠标移到有问题的CheckBox
上并释放它。)
您可以为RequestBringIntoView事件创建一个简单的事件处理程序,并将其与CheckBox
中的DataTemplate
一起使用,并使用Handled
属性来抑制该事件,它不会再传播(下面对我有用)。
XAML:
<DataTemplate>
<CheckBox Width="125" IsChecked="{Binding Path=On}" RequestBringIntoView="RequestBringIntoViewSuppressor">
<TextBlock Text="{Binding Path=StrValue}" TextWrapping="Wrap"/>
</CheckBox>
</DataTemplate>
C#:
private void RequestBringIntoViewSuppressor(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
如果CheckBox
略微偏离屏幕,你的{{1}}现在就不会正确地进入视野,但它不会意外跳跃,你可以根据需要进一步自定义处理程序。