WPF 滚动和焦点改变问题

发布于 2024-11-05 19:42:36 字数 4356 浏览 1 评论 0原文

我的 WPF 应用程序滚动时遇到问题。

这是交易。我的 UI 如下:

ScrollViewer

我的应用程序的作用是充当许多应用程序的中央枢纽并启动它们。管理员可以启动其他用户记录的转储。 因此,我有一个 ListView,显示应用程序列表,如果需要,该列表是可滚动的。 我定义了一个 GroupStyle 来显示扩展器并模拟 Windows 资源管理器视图。 一切正常,我只是有一个问题:当用鼠标滚轮滚动时,透明蓝色的组件(“启动模式”)似乎抓住了焦点并停止滚动。 这尤其意味着,如果我的鼠标位于此控制之外的任何位置,则滚动是可以的。但是每当鼠标进入这个控件时,我就无法再滚动了。 我尝试修改属性 Focusable 并将其设置为 False ,但没有任何改变。我猜这最终不是焦点问题。 有人知道如何避免滚动被元素捕获吗?

下面是扩展器内容的一些(简化的,删除了一些无用的属性,以便尽可能清晰)XAML:

<StackPanel Orientation="Vertical"  VerticalAlignment="Top" >

            <ToggleButton>
                <!-- ToggleButton Content... -->
            </ToggleButton>

            <!-- This is the custom component in which you can see "Launch mode" -->
            <my:UcReleaseChooser >
                <!-- Properties there. I tried to set Focusable to False, no impact... -->
            </my:UcReleaseChooser>

        </StackPanel>

以及 UcReleaseChooser 的代码:

<StackPanel HorizontalAlignment="Stretch"
                Focusable="False" ScrollViewer.CanContentScroll="False">

        <ListBox ItemsSource="{Binding ListChosenReleases}" BorderBrush="LightGray" Background="AliceBlue"
                 HorizontalAlignment="Stretch" Focusable="False" ScrollViewer.CanContentScroll="False">

            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" 
                                Focusable="False" ScrollViewer.CanContentScroll="False"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <DockPanel LastChildFill="True" HorizontalAlignment="Stretch"
                               Focusable="False" ScrollViewer.CanContentScroll="False">
                        <TextBlock DockPanel.Dock="Top"
                            HorizontalAlignment="Left" Text="{Binding Key}" 
                                   FontStyle="Italic"/>
                        <ListBox DockPanel.Dock="Bottom"
                            HorizontalAlignment="Right" ItemsSource="{Binding Value}"
                                 BorderBrush="{x:Null}" Background="AliceBlue"
                                 Focusable="False" ScrollViewer.CanContentScroll="False">
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <UniformGrid Focusable="False"/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>

                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <-- Blah blah about style -->
                                </Style>
                            </ListBox.ItemContainerStyle>


                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <RadioButton Content="{Binding Key}" Margin="3"
                                            IsChecked="{Binding Path=IsSelected, Mode=TwoWay, 
                                                        RelativeSource={RelativeSource FindAncestor, 
                                                            AncestorType={x:Type ListBoxItem}}}" 
                                                 Focusable="False" ScrollViewer.CanContentScroll="False"/>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </DockPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>

        </ListBox>

    </StackPanel>

如您所见,UcReleaseChooser< /code> 包含 RadioButton 列表的列表。我尝试设置 Focusable & CanContentScrollFalse 在任何看起来合适的地方,但控件一直阻止主 UI 滚动...

我想我应该更改另一个属性...有什么想法吗?

谢谢!

I am having a problem with scrolling for my WPF application.

Here is the deal. My UI is the following:

ScrollViewer

The role of my application is to act as a central hub for many applications and launch them. An admin can launch a dump recorded by another user.
Therefore, I have a ListView, showing the application list, which is scrollable if needed.
I defined a GroupStyle in order to show expanders and emulate a Windows Explorer view.
Everything works fine, I just have a problem: when scrolling with the mouse wheel, the component in clear blue ("Launch mode") seems to be catching the focus and stop scrolling.
This means especially that if my mouse is anywhere out of this control, the scrolling is okay. But whenever the mouse enters this control, I can't scroll anymore.
I tried to modify the property Focusable and set it to False everywhere I could but nothing changed. I'd guess that it is finally not a focus problem.
Anybody has an idea on how to avoid the scrolling to be caught by the element?

Here is some (simplified, removed some useless properties so as to make it as clear as possible) XAML for the expander's content:

<StackPanel Orientation="Vertical"  VerticalAlignment="Top" >

            <ToggleButton>
                <!-- ToggleButton Content... -->
            </ToggleButton>

            <!-- This is the custom component in which you can see "Launch mode" -->
            <my:UcReleaseChooser >
                <!-- Properties there. I tried to set Focusable to False, no impact... -->
            </my:UcReleaseChooser>

        </StackPanel>

And the code for UcReleaseChooser:

<StackPanel HorizontalAlignment="Stretch"
                Focusable="False" ScrollViewer.CanContentScroll="False">

        <ListBox ItemsSource="{Binding ListChosenReleases}" BorderBrush="LightGray" Background="AliceBlue"
                 HorizontalAlignment="Stretch" Focusable="False" ScrollViewer.CanContentScroll="False">

            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" 
                                Focusable="False" ScrollViewer.CanContentScroll="False"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <DockPanel LastChildFill="True" HorizontalAlignment="Stretch"
                               Focusable="False" ScrollViewer.CanContentScroll="False">
                        <TextBlock DockPanel.Dock="Top"
                            HorizontalAlignment="Left" Text="{Binding Key}" 
                                   FontStyle="Italic"/>
                        <ListBox DockPanel.Dock="Bottom"
                            HorizontalAlignment="Right" ItemsSource="{Binding Value}"
                                 BorderBrush="{x:Null}" Background="AliceBlue"
                                 Focusable="False" ScrollViewer.CanContentScroll="False">
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <UniformGrid Focusable="False"/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>

                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <-- Blah blah about style -->
                                </Style>
                            </ListBox.ItemContainerStyle>


                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <RadioButton Content="{Binding Key}" Margin="3"
                                            IsChecked="{Binding Path=IsSelected, Mode=TwoWay, 
                                                        RelativeSource={RelativeSource FindAncestor, 
                                                            AncestorType={x:Type ListBoxItem}}}" 
                                                 Focusable="False" ScrollViewer.CanContentScroll="False"/>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </DockPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>

        </ListBox>

    </StackPanel>

As you can see, the UcReleaseChooser contains a list of RadioButton lists. I tried to set Focusable & CanContentScroll to False everywhere it seemed appropriate, but the control keeps preventing the main UI to scroll...

I guess I should change another property... Any idea?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遗忘曾经 2024-11-12 19:42:36

问题在于 ListBox,或更具体地说,是 ListBox 模板中的 ScrollViewer。这是获取滚动事件并在 ListView 中的外部 ScrollViewer 看到它们之前消耗它们。

如果可能的话,我建议用 ItemsControl 替换 ListBox 。但是,这意味着不会有 SelectedItem 属性。如果您需要,我建议将 ScrollViewer.Horizo​​ntalScrollBarVisibility (或 VerticalScrollBarVisibility)设置为 Disabled。如果做不到这一点,我只能建议重新模板化 ListBox 以使其根本不包含 ScrollViewer

The problem is the ListBox, or more specifically, the ScrollViewer within the ListBox's template. This is getting your scroll events and consuming them before the outer ScrollViewer in the ListView even sees them.

I would advise replacing the ListBox with an ItemsControl if possible. However, that implies there will be no SelectedItem property. If you need that, I would suggest setting ScrollViewer.HorizontalScrollBarVisibility (or VerticalScrollBarVisibility) to Disabled. Failing that, I can only suggest re-templating ListBox to not contain a ScrollViewer at all.

蹲在坟头点根烟 2024-11-12 19:42:36

我遇到了滚动查看器内的列表框窃取焦点的问题(滚动查看器内有多个列表框)。因此,我创建了一个附加属性,它拒绝列表框滚动的能力。因此,包含列表框的滚动查看器可以滚动

您的控件是一个列表框,因此应该按原样工作,但没有理由将扩展限制为列表框;这只是为了符合我的确切目的。

 public static class ListboxExtensions
{
    public static DependencyProperty IgnoreScrollProperty = DependencyProperty.RegisterAttached("IgnoreScroll", typeof(bool), typeof(ListboxExtensions), new UIPropertyMetadata(false, IgnoreScrollChanged));

    public static bool GetIgnoreScroll(DependencyObject dependencyObject)
    {
        return (bool)dependencyObject.GetValue(IgnoreScrollProperty);
    }

    public static void SetIgnoreScroll(DependencyObject dependencyObject, bool value)
    {
        dependencyObject.SetValue(IgnoreScrollProperty, value);
    }

    private static void IgnoreScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var newValue = (bool)e.NewValue;
        var oldValue = (bool)e.OldValue;

        var frameworkElement = d as FrameworkElement;
        if (frameworkElement == null) return;

        if (!newValue || oldValue || frameworkElement.IsFocused) return;

        var lb = frameworkElement as ListBox;
        if (lb == null) return;

        lb.PreviewMouseWheel += LbOnPreviewMouseWheel;
    }

    private static void LbOnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (!(sender is ListBox) || e.Handled) return;

        e.Handled = true;
        var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
            {
                RoutedEvent = UIElement.MouseWheelEvent,
                Source = sender
            };

        var parent = ((Control)sender).Parent as UIElement;
        if (parent != null) parent.RaiseEvent(eventArg);
    }
}

然后在您的 XAML 中,您只需将其放在列表框中:

 <ListBox extensions:ListboxExtensions.IgnoreScroll="True">

当然,请记住将命名空间包含在 XAML 顶部的扩展中:

xmlns:extensions="clr-namespace:UI.Extensions"

I had an issue with a listbox stealing focus inside a scrollviewer (I have multiple listboxes inside the scrollviewer). So I created an attached property which denies the listbox the ability to scroll. So therefore the scrollviewer which is housing the listbox can scroll

Your control is a listbox, so this should work as is, but there is no reason the Extension should be limited to a Listbox; it just is to match my exact purpose.

 public static class ListboxExtensions
{
    public static DependencyProperty IgnoreScrollProperty = DependencyProperty.RegisterAttached("IgnoreScroll", typeof(bool), typeof(ListboxExtensions), new UIPropertyMetadata(false, IgnoreScrollChanged));

    public static bool GetIgnoreScroll(DependencyObject dependencyObject)
    {
        return (bool)dependencyObject.GetValue(IgnoreScrollProperty);
    }

    public static void SetIgnoreScroll(DependencyObject dependencyObject, bool value)
    {
        dependencyObject.SetValue(IgnoreScrollProperty, value);
    }

    private static void IgnoreScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var newValue = (bool)e.NewValue;
        var oldValue = (bool)e.OldValue;

        var frameworkElement = d as FrameworkElement;
        if (frameworkElement == null) return;

        if (!newValue || oldValue || frameworkElement.IsFocused) return;

        var lb = frameworkElement as ListBox;
        if (lb == null) return;

        lb.PreviewMouseWheel += LbOnPreviewMouseWheel;
    }

    private static void LbOnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (!(sender is ListBox) || e.Handled) return;

        e.Handled = true;
        var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
            {
                RoutedEvent = UIElement.MouseWheelEvent,
                Source = sender
            };

        var parent = ((Control)sender).Parent as UIElement;
        if (parent != null) parent.RaiseEvent(eventArg);
    }
}

And then in your XAML, you just put this on the listbox:

 <ListBox extensions:ListboxExtensions.IgnoreScroll="True">

Of course, remembering to include the namespace to your extensions in the top of the XAML:

xmlns:extensions="clr-namespace:UI.Extensions"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文