gpt4 book ai didi

c# - WPF:DataGrid 上的水平滚动查看器在重新实例化绑定(bind)的 ObservableCollection 时捕捉到右侧

转载 作者:太空宇宙 更新时间:2023-11-03 14:40:33 25 4
gpt4 key购买 nike

我目前在 WPF 中遇到一个问题,当重新实例化绑定(bind)的 ObservableCollection 时,DataGrid 的水平 ScrollViewer 会捕捉到可能的滚动空间的右侧(显示 DataGrid 最右边的内容)。

即使我在调用绑定(bind)事件时触发手动将 Horizo​​ntalOffset 设置为 0 的行为,并在重新绑定(bind)列表后立即调用该事件,0 也会被忽略并且捕捉再次转到右侧。我认为这与 ScrollViewer 中的操作顺序和命令队列有关。

这似乎应该是默认行为(我不确定为什么您会希望在填充数据时滚动条默认对齐到右侧)。有人知道解决此问题的方法吗?

根据要求,我的复制项目中的代码文件。

MainWindow.xaml

<Window x:Class="WpfScrollViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfScrollViewer"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button Content="Rebind" Command="{Binding RebindCommand}"/>
<Button Content="Clear and Set" Command="{Binding ClearCommand}"/>
</StackPanel>

<DataGrid ItemsSource="{Binding People}" Grid.Row="1" HorizontalScrollBarVisibility="Visible" FontSize="30">

</DataGrid>
</Grid>

Person.cs

namespace WpfScrollViewer
{
public class Person
{
public string FirstNames { get; set; }

public string LastName { get; set; }

public int Age { get; set; }

public string Address { get; set; }

public string PostCode { get; set; }

public string PhoneNumber { get; set; }
}
}

DelegateCommand.cs

using System;
using System.Windows.Input;

namespace WpfScrollViewer
{
public class DelegateCommand : ICommand
{
private readonly Action _fn;
private readonly Func<bool> _canExecute;

public event EventHandler CanExecuteChanged;

public DelegateCommand(Action fn, Func<bool> canExecute = null)
{
_fn = fn;
_canExecute = canExecute;
}

public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}

return _canExecute();
}

public void Execute(object parameter)
{
_fn();
}
}
}

MainViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;

namespace WpfScrollViewer
{
public class MainViewModel : INotifyPropertyChanged
{
private readonly Random _random = new Random();

private ObservableCollection<Person> _people;

public ObservableCollection<Person> People
{
get => _people;
set
{
if (_people == value)
{
return;
}

_people = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(People)));
}
}

public event PropertyChangedEventHandler PropertyChanged;

public ICommand RebindCommand { get; }

public ICommand ClearCommand { get; }

public MainViewModel()
{
RebindCommand = new DelegateCommand(RebindPeople);
ClearCommand = new DelegateCommand(ClearAndSetPeople);
}

private void RebindPeople()
{
People = new ObservableCollection<Person>(GetPeople());
}

private void ClearAndSetPeople()
{
var people = GetPeople();
People.Clear();
foreach (var person in people)
{
People.Add(person);
}
}

private List<Person> GetPeople()
{
var people = new List<Person>
{
new Person
{
FirstNames = "John",
LastName = "Doe",
Address = "17 Random Street",
PostCode = "RN32 2JR",
Age = 31,
PhoneNumber = "07647123456"
},
new Person
{
FirstNames = "Jane",
LastName = "Doe",
Address = "17 Random Street",
PostCode = "RN32 2JR",
Age = 30
},
new Person
{
FirstNames = "Jack",
LastName = "Freens",
Address = "37 Badboi Lane",
Age = 30
},
new Person
{
FirstNames = "Richard",
LastName = "Brodget",
Address = "69 Meme Street",
Age = 31
},
new Person
{
FirstNames = "Sam",
LastName = "Orfitt",
Address = "16 Withernsea Road",
Age = 29
},
new Person
{
FirstNames = "Tom",
LastName = "Orfitt",
Address = "16 Withernsea",
Age = 27
}
};

var rmCount = _random.Next(1, 4);
for (var i = 0; i < rmCount; i++)
{
people.RemoveAt(_random.Next(people.Count));
}

return people;
}
}
}

使用“重新绑定(bind)”按钮会显示我在上面描述的行为。确保您稍微向右滚动,水平滚动条将在重新绑定(bind)时捕捉到右侧。如果滚动条完全位于左侧,水平滚动条将正确地向左对齐,正如我希望它在所有情况下都这样做。

干杯

最佳答案

这是由列自动生成功能引起的。每次更改数据时,它都会删除所有列(我猜在这个阶段滚动条位置丢失)并根据传递的数据创建新列。如果您静态定义列并使用 AutoGenerateColumns="False" 参数禁用该功能,它不会重置滚动条位置。

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding People}" Grid.Row="1" HorizontalScrollBarVisibility="Visible" FontSize="30">
<DataGrid.Columns>
<DataGridTextColumn Header="FirstNames" Binding="{Binding FirstNames}" />
<DataGridTextColumn Header="LastName" Binding="{Binding LastName}" />
<DataGridTextColumn Header="Age" Binding="{Binding Age}" />
<DataGridTextColumn Header="Address" Binding="{Binding Address}" />
<DataGridTextColumn Header="PostCode" Binding="{Binding PostCode}" />
<DataGridTextColumn Header="PhoneNumber" Binding="{Binding PhoneNumber}" />
</DataGrid.Columns>
</DataGrid>

如果您想动态生成列并且还需要记住滚动条位置,您可以使用反射从代码后面生成列。缺点是不能绑定(bind),必须手动生成。例如

<DataGrid AutoGenerateColumns="False" Loaded="DataGrid_Loaded" ItemsSource="{Binding People}" Grid.Row="1" HorizontalScrollBarVisibility="Visible" FontSize="30">
</DataGrid>

和DataGrid_Loaded:

DataGrid dg = (DataGrid)sender;
MainViewModel mvm = (MainViewModel)this.DataContext;
Type classType = typeof(Person);
PropertyInfo[] properties = classType.GetProperties();
foreach (PropertyInfo prop in properties) {
dg.Columns.Add(new DataGridTextColumn() {
Binding = new Binding(prop.Name),
Header = prop.Name
});
}

关于c# - WPF:DataGrid 上的水平滚动查看器在重新实例化绑定(bind)的 ObservableCollection 时捕捉到右侧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57090666/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com