C# WPF:DataGrid上的水平滚动查看器在重新启动绑定的ObservableCollection时捕捉到右侧

C# WPF:DataGrid上的水平滚动查看器在重新启动绑定的ObservableCollection时捕捉到右侧,c#,wpf,C#,Wpf,我目前在WPF中遇到一个问题,当重新启动绑定的ObservableCollection时,DataGrid的水平滚动查看器会捕捉到可能的滚动空间的右侧(显示DataGrid最右侧的内容) 即使在调用绑定事件时触发手动将HorizontalOffset设置为0的行为,并在重新绑定列表后立即调用该事件,0也会被忽略,快照会再次转到右侧。我假设这与ScrollViewer中的操作顺序和命令队列有关 这似乎应该是默认行为(我不知道为什么在填充数据时,您会希望滚动条默认捕捉到右侧)。有人知道这个问题的解决

我目前在WPF中遇到一个问题,当重新启动绑定的ObservableCollection时,DataGrid的水平滚动查看器会捕捉到可能的滚动空间的右侧(显示DataGrid最右侧的内容)

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

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

根据请求,从我的复制项目中删除代码文件

main window.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>
DelegateCommand.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; }
    }
}
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();
        }
    }
}
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;
        }
    }
}
使用系统;
使用System.Windows.Input;
命名空间WpfScrollViewer
{
公共类DelegateCommand:ICommand
{
私人只读操作_fn;
私有只读功能可执行;
公共事件处理程序CanExecuteChanged;
公共DelegateCommand(操作fn,Func canExecute=null)
{
_fn=fn;
_canExecute=canExecute;
}
公共布尔CanExecute(对象参数)
{
如果(_canExecute==null)
{
返回true;
}
返回_canExecute();
}
public void Execute(对象参数)
{
_fn();
}
}
}
MainViewModel.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; }
    }
}
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();
        }
    }
}
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;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用系统组件模型;
使用System.Windows.Input;
命名空间WpfScrollViewer
{
公共类MainViewModel:INotifyPropertyChanged
{
private readonly Random_Random=new Random();
私人可观察的收集人;
公众观察收集人
{
获取=>\u人;
设置
{
如果(_people==值)
{
返回;
}
_人=价值;
PropertyChanged?.Invoke(这是新的propertychangedventargs(name of(People));
}
}
公共事件属性更改事件处理程序属性更改;
公共ICommand重新绑定命令{get;}
公共ICommand ClearCommand{get;}
公共主视图模型()
{
RebindCommand=新的委托人命令(REBINDPEOPEN);
ClearCommand=新的DelegateCommand(ClearAndSetPeople);
}
私人关系
{
People=新的observeCollection(GetPeople());
}
私有void ClearAndSetPeople()
{
var people=GetPeople();
人。清除();
foreach(人与人之间的变量)
{
人。添加(人);
}
}
私有列表GetPeople()
{
var people=新列表
{
新人
{
FirstNames=“约翰”,
LastName=“Doe”,
地址=“17随机街”,
邮编=“RN32 2JR”,
年龄=31岁,
电话号码=“07647123456”
},
新人
{
FirstNames=“Jane”,
LastName=“Doe”,
地址=“17随机街”,
邮编=“RN32 2JR”,
年龄=30
},
新人
{
FirstNames=“杰克”,
LastName=“Freens”,
地址=“Badboi巷37号”,
年龄=30
},
新人
{
FirstNames=“Richard”,
LastName=“Brodget”,
地址=“Meme街69号”,
年龄=31
},
新人
{
FirstNames=“山姆”,
LastName=“Orfitt”,
地址=“威森西路16号”,
年龄=29
},
新人
{
名字=“汤姆”,
LastName=“Orfitt”,
Address=“16威瑟森西亚”,
年龄=27
}
};
var rmCount=_random.Next(1,4);
对于(变量i=0;i
使用“重新绑定”按钮显示我上面描述的行为。确保稍微向右滚动,重新绑定时水平滚动条将向右捕捉。如果滚动条完全向左移动,水平滚动条将正确地向左移动,就像我希望在所有情况下一样


欢呼声

这是由栏目自动生成功能引起的。每次更改数据时,它都会删除所有列(在此阶段中,滚动条位置丢失),并根据传递的数据创建新列。如果静态定义列并使用
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>

请与我们分享您的代码和其他问题详细信息。我已经添加了一些示例代码。