не работает прокрутка в ListBox из-за DataGrid

279
14 августа 2017, 08:09

Добрый день. Обнаружил такую проблему. Есть разметка такая:

<Grid>
        <ListBox>
            <ListBoxItem>
                <DataGrid x:Name="grid" ItemsSource="{Binding}" >
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Имя"  Binding="{Binding FirstName}"/>
                        <DataGridComboBoxColumn Header="Пол"  SelectedItemBinding="{Binding Status}"/>
                    </DataGrid.Columns>
                </DataGrid>
            </ListBoxItem>
            <ListBoxItem>
                <DataGrid x:Name="grid2" ItemsSource="{Binding}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Имя"  Binding="{Binding FirstName}"/>
                        <DataGridComboBoxColumn Header="Пол"  SelectedItemBinding="{Binding Status}"/>
                    </DataGrid.Columns>
                </DataGrid>
            </ListBoxItem>
            <ListBoxItem>
                <DataGrid x:Name="grid3" ItemsSource="{Binding}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Имя"  Binding="{Binding FirstName}"/>
                        <DataGridComboBoxColumn Header="Пол"  SelectedItemBinding="{Binding Status}"/>
                    </DataGrid.Columns>
                </DataGrid>
            </ListBoxItem>
        </ListBox>
    </Grid>

И код с данными, если вам необходим:

public class Customer
    {
        public string FirstName { get; set; }
        public string Status { get; set; }
    }
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            ObservableCollection<Customer> custdata = GetData();
            grid.DataContext = custdata;
            grid2.DataContext = custdata;
            grid3.DataContext = custdata;
        }
        public ObservableCollection<Customer> GetData()
        {
            ObservableCollection<Customer> data = new ObservableCollection<Customer>()
            {
                new Customer{ FirstName="Дмитрий", Status="Мужской"},
                new Customer{ FirstName="Ирина", Status="Женский"},
                new Customer{ FirstName="Владимир", Status="Мужской"},
                new Customer{ FirstName="Юрий", Status="Мужской"},
                new Customer{ FirstName="Дмитрий", Status="Мужской"},
            };
            return data;
        }
    }

Это всё лишь для примера. ТАк вот. Когда курсор находиться на контенте в DataGrid и есть вертикальная полоса прокрутки у ListBox, то эта самая прокрутка не работает. Пытался отключить все скролы у DataGrid - не помогло. Помогло установить IsHitTestVisible="False" у DataGrid, но тогда не работает редактирование. Какое есть решение, чтобы ListBox прокручивался независимо от всех элементов? Мне прокрутка в DataGrid вообще не нужна и если вариант отключить как-то её в угоду ListBox - То это решение тоже бы подошло. Заранее спасибо.

Answer 1

Ваша проблема решается следующим образом:

1) Вам не нужно вручную добавлять каждый раз элемент ListBoxItem в ListBox, для того что бы отобразить в нем элемент DataGrid. Для этого достаточно определить ItemTemplate.

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <GroupBox>
                <DataGrid>
                    <DataGrid.Columns>                  
                        <DataGridTextColumn />
                        <DataGridTextColumn />
                    </DataGrid.Columns>
                </DataGrid>
            </GroupBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

2) Затем на понадобиться Behavior, который будет пробрасывать событие MouseWheel, для того что бы работала прокрутка в DataGrid.

public class MouseWheelBehavior : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseWheel += OnPreviewMouseWheel;
    }
    protected override void OnDetaching()
    {
        AssociatedObject.PreviewMouseWheel -= OnPreviewMouseWheel;
        base.OnDetaching();
    }
    private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
        var args = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
        args.RoutedEvent = UIElement.MouseWheelEvent;
        AssociatedObject.RaiseEvent(args);
    }
}

3) Далее добавляем созданный Behavior к DataGrid.

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <GroupBox>
                <DataGrid>
                    <DataGrid.Columns>                  
                        <DataGridTextColumn />
                        <DataGridTextColumn />
                    </DataGrid.Columns>
                    <i:Interaction.Behaviors>
                        <wpfApplication1:MouseWheelBehavior />
                    </i:Interaction.Behaviors>
                </DataGrid>
            </GroupBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

4) Создаем модели, которые будем отображать в нашем списке. В простейшем виде, они могут выглядеть так:

public class Customer
{
    public string Name { get; set; }
    public int Age { get; set; }
}
public class Item
{
    public List<Customer> Customers { get; }
    public string TableName { get; set; }
    public Item()
    {
        Customers = new List<Customer>();
    }
}

5) Итоговая разметка:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:viewModel="clr-namespace:WpfApplication1.ViewModel"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1">
    <Grid>
        <ListBox HorizontalContentAlignment="Stretch"
                 ItemsSource="{Binding Items}"
                 ScrollViewer.CanContentScroll="False"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <GroupBox Header="{Binding TableName}">
                        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Customers}">
                            <DataGrid.Columns>
                                <DataGridTextColumn Width="*" Binding="{Binding Name}" Header="Имя" />
                                <DataGridTextColumn Width="100" Binding="{Binding Age}" Header="Возраст" />
                            </DataGrid.Columns>
                            <i:Interaction.Behaviors>
                                <wpfApplication1:MouseWheelBehavior />
                            </i:Interaction.Behaviors>
                        </DataGrid>
                    </GroupBox>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

6) Во viewModel заполняем тестовыми данными нашу коллекцию.

public class MainViewModel : ViewModelBase
{
    public ObservableCollection<Item> Items { get; }
    public MainViewModel()
    {
        Items = new ObservableCollection<Item>();
        for (int i = 0; i < 100; i++)
        {
            var item = new Item()
            {
                TableName = $"Таблица {i + 1}"
            };
            for (int j = 0; j < 500; j++)
            {
                item.Customers.Add(new Customer()
                {
                    Name = $"Имя {j + 1}",
                    Age = j + 5
                });
            }
            Items.Add(item);
        }
    }
}
Answer 2

Оберните ListBox в

<ScrollViewer x:Name="MyScrollViewer" >

Добавьте в ListBox событие

PreviewMouseWheel="grid_MouseWheel"

Обработайте событие:

private void grid_MouseWheel(object sender, MouseWheelEventArgs e)
{
    if (e.Delta < 0) MyScrollViewer.LineDown(); else MyScrollViewer.LineUp();
}
READ ALSO
Как ограничить добавление товара в Modx Revolution имея тв поле остаток?

Как ограничить добавление товара в Modx Revolution имея тв поле остаток?

Ограничение максимального числа ввода добавления в корзину minishop2 из tv availability Чтобы расширить поле availability читаем: //githubcom/bezumkin/miniShop2/blob/master/assets/components/minishop2/js/web/default

461
SVG , пересечение элементов

SVG , пересечение элементов

Доброе время сутокРисую svg , используя snap

408
Непонятные подсказки в VS Code для JavaScript. Как отключить IntelliSense в Visual Studio Code?

Непонятные подсказки в VS Code для JavaScript. Как отключить IntelliSense в Visual Studio Code?

Проверил, из плагинов ничего такого не установлено, но в JS постоянно вылазят эти подсказкиКак их отключить?

399
Вызов диалога выбора файла из JavaScript

Вызов диалога выбора файла из JavaScript

Как правильно вызывать диалог выбора файла программно из JavaScript? На данный момент создаю элемент input[type="file"] и вызываю его метод click:

362