滚动到顶部/底部时,Wpf 禁用重复按钮

标签 wpf xaml listbox repeatbutton

我正在制作一个使用列表框的触摸屏界面。
我在列表框上方和下方有一个用于向上/向下翻页的按钮。

我试图让它在向上滚动时页面按钮被禁用的位置。
并且当一直向下滚动时,pagedown 按钮也会被禁用。

这是我的 Styles.xaml 中用于列表框的代码

<Style x:Key="{x:Type ListBox}" TargetType="{x:Type ListBox}">  
    <Setter Property="Template">  
        <Setter.Value>  
            <ControlTemplate x:Key="{x:Type ListBox}" TargetType="{x:Type ListBox}">  
                <DockPanel>  
                    <RepeatButton x:Name="LineUpButton" DockPanel.Dock="Top"  
                        HorizontalAlignment="Stretch"   
                        Height="50"  
                        Content="/\"  
                        Command="{x:Static ScrollBar.PageUpCommand}"  
                        CommandTarget="{Binding ElementName=scrollviewer}" />    
                    <RepeatButton x:Name="LineDownButton" DockPanel.Dock="Bottom"  
                        HorizontalAlignment="Stretch"  
                        Height="50"  
                        Content="\/"  
                        Command="{x:Static ScrollBar.PageDownCommand}"  
                        CommandTarget="{Binding ElementName=scrollviewer}" />  
                    <Border BorderThickness="1" BorderBrush="Gray" Background="White">    
                        <ScrollViewer x:Name="scrollviewer">  
                            <ItemsPresenter/>  
                        </ScrollViewer>  
                    </Border>  
                </DockPanel>  
            </ControlTemplate>  
        </Setter.Value>  
    </Setter>  
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>  
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>  
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />  
</Style> 

这是我实例化列表框的地方
<ListBox SelectedItem="{Binding SelectedCan}" ItemsSource="{Binding Path=SelectedKioskCashCans}">  
    <ListBox.ItemTemplate>  
        <DataTemplate>  
            <ContentPresenter Content="{Binding image}" MaxWidth="75" />  
        </DataTemplate>  
     </ListBox.ItemTemplate>  
     <ListBox.ItemsPanel>  
         <ItemsPanelTemplate>  
             <VirtualizingStackPanel Orientation="Vertical"/>  
         </ItemsPanelTemplate>  
     </ListBox.ItemsPanel>  
</ListBox> 

我昨天四处搜寻,没有运气。
我希望能够在 xaml 中完成这一切。

我在按钮上使用了图片,但为了便于阅读,我把它们取出来了,
他们真的看起来像……
<RepeatButton x:Name="LineUpButton" DockPanel.Dock="Top" HorizontalAlignment="Stretch" 
    Height="50"      
    Command="{x:Static ScrollBar.PageUpCommand}"      
    CommandTarget="{Binding ElementName=scrollviewer}">
        <RepeatButton.Template>
             <ControlTemplate TargetType="{x:Type RepeatButton}">
                 <Grid>
                     <Image Name="Normal" Source="/Images/up.png"/>
                     <Image Name="Pressed" Source="/Images/up.png" Visibility="Hidden"/>
                 </Grid>
                 <ControlTemplate.Triggers>
                      <Trigger Property="IsPressed" Value="True">
                          <Setter TargetName="Normal" Property="Visibility" Value="Hidden"/>
                          <Setter TargetName="Pressed" Property="Visibility" Value="Visible"/>
                      </Trigger>
                  </ControlTemplate.Triggers>
             </ControlTemplate>
        </RepeatButton.Template>
   </RepeatButton>

最佳答案

只需使用 CanExecute PageUpCommand 的方法为了那个原因。返回 false如果没有剩余页面,则该按钮将自动禁用。

编辑:

我创建了一个简单的 attached behavior可以用来解决这个问题。只需在 ScrollViewer 上设置以下附加属性:

<ScrollViewer x:Name="scrollviewer"
              z:ScrollBarCommandsCanExecuteFixBehavior.IsEnabled="True">  
     <ItemsPresenter/>  
</ScrollViewer> 

这是行为的源代码:
public static class ScrollBarCommandsCanExecuteFixBehavior
{
    #region Nested Types

    public class CommandCanExecuteMonitor<T> where T : UIElement
    {
        protected T Target { get; private set; }

        protected CommandCanExecuteMonitor(T target, RoutedCommand command)
        {
            Target = target;

            var binding = new CommandBinding(command);

            binding.CanExecute += OnCanExecute;

            target.CommandBindings.Add(binding);
        }

        protected virtual void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {

        }
    }

    public class PageUpCanExecuteMonitor : CommandCanExecuteMonitor<ScrollViewer>
    {
        public PageUpCanExecuteMonitor(ScrollViewer scrollViewer)
            : base(scrollViewer, ScrollBar.PageUpCommand)
        {
        }

        protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (e.Handled)
            {
                return;
            }

            if (Equals(Target.VerticalOffset, 0.0))
            {
                e.CanExecute = false;
                e.Handled = true;
            }
        }
    }

    public class PageDownCanExecuteMonitor : CommandCanExecuteMonitor<ScrollViewer>
    {
        public PageDownCanExecuteMonitor(ScrollViewer scrollViewer)
            : base(scrollViewer, ScrollBar.PageDownCommand)
        {
        }

        protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (e.Handled)
            {
                return;
            }

            if (Equals(Target.VerticalOffset, Target.ScrollableHeight))
            {
                e.CanExecute = false;
                e.Handled = true;
            }
        }
    }

    #endregion

    #region IsEnabled Attached Property

    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool) obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached("IsEnabled", typeof (bool), typeof (ScrollBarCommandsCanExecuteFixBehavior), new PropertyMetadata(false, OnIsEnabledChanged));

    private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((bool) e.NewValue)
        {
            var scrollViewer = d as ScrollViewer;

            if (scrollViewer != null)
            {
                OnAttached(scrollViewer);
            }
            else
            {
                throw new NotSupportedException("This behavior only supports ScrollViewer instances.");
            }
        }
    }

    private static void OnAttached(ScrollViewer target)
    {
        SetPageUpCanExecuteMonitor(target, new PageUpCanExecuteMonitor(target));
        SetPageDownCanExecuteMonitor(target, new PageDownCanExecuteMonitor(target));
    }

    #endregion

    #region PageUpCanExecuteMonitor Attached Property

    private static void SetPageUpCanExecuteMonitor(DependencyObject obj, PageUpCanExecuteMonitor value)
    {
        obj.SetValue(PageUpCanExecuteMonitorProperty, value);
    }

    private static readonly DependencyProperty PageUpCanExecuteMonitorProperty =
        DependencyProperty.RegisterAttached("PageUpCanExecuteMonitor", typeof (PageUpCanExecuteMonitor), typeof (ScrollBarCommandsCanExecuteFixBehavior), new PropertyMetadata(null));

    #endregion

    #region PageDownCanExecuteMonitor Attached Property

    private static void SetPageDownCanExecuteMonitor(DependencyObject obj, PageDownCanExecuteMonitor value)
    {
        obj.SetValue(PageDownCanExecuteMonitorProperty, value);
    }

    private static readonly DependencyProperty PageDownCanExecuteMonitorProperty =
        DependencyProperty.RegisterAttached("PageDownCanExecuteMonitor", typeof (PageDownCanExecuteMonitor), typeof (ScrollBarCommandsCanExecuteFixBehavior), new PropertyMetadata(null));

    #endregion
}

基本思想是我们添加一个 CommandBindingScrollViewer对于每个命令并订阅 CanExecute 这些绑定(bind)上的事件。在事件处理程序中,我们检查滚动的当前位置并设置 e.CanExecute相应的属性(property)。

关于滚动到顶部/底部时,Wpf 禁用重复按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4795066/

相关文章:

c# - 后台 worker 不工作 WPF

c# - WPF DataGrid 自动生成的列,更改标题名称

.net - 单独程序集中的 ResourceDictionary

wpf - 限制其容器内的 WPF 元素宽度

c# - 以 C# 形式将文本框中的信息显示到列表框中

angular - 无法将第二个数组绑定(bind)到 angular-dual-listbox

c# - 如何在 OxyPlot 中强制 x 轴保持在 0?

c# - 重新托管的 WF4 设计器中参数的默认值无法解析

c# - 在 UWP 中,有没有一种方法可以让列相互环绕?

WPF - 绑定(bind)到用户控件之间列表框的选定项