#c# #wpf #mvvm #datagrid
#c# #wpf #mvvm #сетка данных
Вопрос:
Я хочу, чтобы моя сетка данных прокручивалась только колесом мыши, когда вы одновременно нажимаете клавишу ctrl, иначе я хочу прокрутить страницу. Я новичок в wpf и mvvm, которые я использую в своем приложении.
Это страница, содержащая сетку данных:
<Page x:Class="Projectname.ChapterPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Projectname"
xmlns:core="clr-namespace:Projectname.Core;assembly=Projectname.Core"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="900"
Title="ChapterPage">
<StackPanel>
<TextBlock Grid.Column="0"
Grid.ColumnSpan="2"
Text="Kapitel"
Style="{StaticResource HeaderText}"
Foreground="{StaticResource
ForegroundVeryLightBrush}"
FontSize="{StaticResource FontSizeLarge}"
FontWeight="Bold"
Margin="50 -45 50 15"/>
<Border Background="{StaticResource BlueBrush}"
CornerRadius="10"
Margin="10"
MinHeight="45"
Padding="2">
<StackPanel HorizontalAlignment="Center"
Orientation="Horizontal">
<Button Command="{Binding SaveCommand}"
Style="{StaticResource IconGrowButton}"
ToolTip="Speichern"
Margin="10 0"
MaxHeight="30"
MinWidth="30"
Cursor="Hand">
<Image Source="../Images/Icons/Save.png" />
</Button>
<Button Command="{Binding DeleteCommand}"
Style="{StaticResource IconGrowButton}"
ToolTip="Löschen"
MaxHeight="30"
MinWidth="30"
Margin="10 0 80 0"
Cursor="Hand">
<Image Source="../Images/Icons/Delete.png" />
</Button>
<Button Command="{Binding ResetCommand}"
Style="{StaticResource IconGrowButton}"
ToolTip="Zurücksetzen"
MaxHeight="30"
MinWidth="30"
Margin="10 0"
Cursor="Hand">
<Image Source="../Images/Icons/Reset.png" />
</Button>
</StackPanel>
</Border>
<DataGrid Margin="15 10"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Chapters,
UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding ChaptersVisibility,
Converter={local:BooleanToVisibilityConverter}}"
SelectedItem="{Binding SelectedChapter}"/>
</StackPanel>
</Page>
Моя страница загружена в окно, а средство просмотра прокрутки содержимого находится в окне.
Это окно:
<Grid>
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Background="{StaticResource RedBrush}">
<Button Command="{Binding NavMenuCommand}"
Style="{StaticResource SystemIconButton}"
Cursor="Hand"
HorizontalAlignment="Left">
<Button.Content>
<Image Source="../Images/Icons/burger-
menue.png"
Height="25"/>
</Button.Content>
</Button>
</Border>
</Grid>
<local:ChapterPage
Padding="8 0"/>
</StackPanel>
<local:NavMenu Margin="0,41,628,0"/>
</Grid>
</ScrollViewer>
Я абсолютно не представляю, как этого добиться, но я не хочу использовать xaml.cs, если я могу этого избежать.
Комментарии:
1. Я отредактировал свой вопрос. Теперь ты меня понимаешь?
2. Спасибо. Затем у вас должно быть два
ScrollViewer
: один со страницей в качестве содержимого и, конечно, один сDataGrid
содержимым. По умолчаниюScrollViewer
при наведении курсора мыши на ввод имеет приоритет. Если цель состоит в том, чтобы разрешить прокрутку без ограничения наведения курсора мыши, тогда вы должны обрабатывать средства просмотра ввода с помощью мыши и прокрутки на общем родительском элементе обоих элементов управления, например, содержащемUserControl
. Не могли бы вы, пожалуйста, показать полный контекст (как средства просмотра прокрутки, так и их родительский элемент)?3. Я добавил код страницы и код окна.
4. Вы действительно хотите прокручивать
DataGrid
, даже если это не видно, т. Е. Ранее прокручивалось вне поля зрения. С точки зрения пользователя ваше желаемое поведение может не добавить никакого значения. Почему он хотел бы изменить свое поведение прокрутки по умолчанию, например, перетащить полосу прокрутки напрямую или использовать колесо мыши, как обычно? Если бы я использовал ваше приложение и глобальную сеть для прокруткиDataGrid
, но вместо этого я прокручиваю всю страницу, я бы счел это довольно раздражающим и тревожным. Вы должны оставить известное и принятое / ожидаемое поведение по умолчанию, если вы значительно не добавите больше ценности для пользовательского интерфейса.5. На самом деле между границей и сеткой данных есть другая сетка, которая содержит пользовательский элемент управления с несколькими текстовыми полями. Для этой сетки требуется много места.
Ответ №1:
Вам необходимо обработать PreviewMouseWheel
событие общим родителем обоих или всех участвующих ScrollViewer
:
MainWindow.xaml
Упрощенный вид:
<Window PreviewMouseWheel="HandleScroll_OnPreviewMouseWheel">
<ScrollViewer x:Name="RootScrollViewer">
<DataGrid x:Name="DataGridToScrollOnKeyPress" />
</ScrollViewer>
</Window>
MainWindow.xaml.cs
private ScrollViewer DataGridScrollViewer { get; set; }
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Find DataGrid by name (in case of multiple DataGrids)
if (TryFindVisualChildElement(this.Root, "DataGridToScrollOnKeyPress", out DataGrid dataGrid))
{
// And get its ScrollViewer (by type)
if (TryFindVisualChildElement(dataGrid, string.Empty, out ScrollViewer scrollViewer))
{
this.DataGridScrollViewer = scrollViewer;
}
}
}
private void HandleScroll_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
// Give the main scroll viewer chance to handle its own scroll,
// if it is the scroll source (preserve default behavior)
if (e.Source == this.Root
amp;amp; !Keyboard.IsKeyDown(Key.LeftCtrl)
amp;amp; !Keyboard.IsKeyDown(Key.RightCtrl))
{
return;
}
e.Handled = true;
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
if (e.Delta < 0)
{
this.DataGridScrollViewer?.LineDown();
}
else
{
this.DataGridScrollViewer?.LineUp();
}
}
else // Some other control is scroll source => scroll main scroll viewer
{
if (e.Delta < 0)
{
this.RootScrollViewer.LineDown();
}
else
{
this.RootScrollViewer.LineUp();
}
}
}
// If the 'childElementName' parameter is NULL, an empty string or whitespace it will be ignored (only the type will be relevant)
public bool TryFindVisualChildElement<TChild>(DependencyObject parent, string childElementName, out TChild childElement)
where TChild : FrameworkElement
{
childElement = null;
if (parent == null)
{
return false;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i )
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is TChild resultElement
amp;amp; (string.IsNullOrWhiteSpace(childElementName) || resultElement.Name.Equals(childElementName, StringComparison.Ordinal)))
{
childElement = resultElement;
return true;
}
if (TryFindVisualChildElement(child, childElementName, out childElement))
{
return true;
}
}
return false;
}
Комментарии:
1. Средство просмотра содержимого прокрутки и сетка данных не находятся в одном и том же xaml. Как я могу это получить?
2. Вы используете метод TryFindVisualChildElement. Посмотрите приведенный выше код и замените родительский элемент (в примере это DataGridToScrollOnKeyPress) на основной экземпляр scroll viewer. Это должно найти сетку данных и перейти к ScrollViewer.
3. Я обновил пример (
OnLoaded()
иTryFindVisualChildElement()
). Вам нужно только настроить имяDataGrid
.4. Когда я пытаюсь получить scrollviewer из datagrid, он возвращает null. После некоторой отладки я обнаружил, что VisualTreeHelper. getChild(DataGrid, i) возвращает 0
5. Важно, чтобы
DatGrid
была загружена до того, как вы сможете получить доступ к ее визуальному дереву. Вы можете создатьDataGridScrollViewer
свойствоstatic
. Затем прикрепитеLoaded
обработчик событий кDataGrid
и используйтеTryFindVisualChildElement
сверху, чтобы получитьScrollViewer
и назначить его статическомуDataGridScrollViewer
. Лучше добавить нулевую проверкуHandleScroll_OnPreviewMouseWheel
перед доступом кDataGridScrollViewer
: например,DataGridScrollViewer?..LineDown();