C# 如何正确处理项目控件大小更改以显示/折叠滚动按钮
我构建了一个用户控件,它应该在应用程序的底部显示一个状态指示器列表。我使用C# 如何正确处理项目控件大小更改以显示/折叠滚动按钮,c#,wpf,xaml,C#,Wpf,Xaml,我构建了一个用户控件,它应该在应用程序的底部显示一个状态指示器列表。我使用ItemsControl创建列表,并使其能够通过鼠标滚轮水平滚动,但还添加了两个按钮(左和右)来替换常用的滚动条(因为滚动条会与外观冲突,在这种情况下会过大) 如果列表中没有足够的项目,或者控件的宽度足以显示所有项目,我想折叠按钮,当然,只要需要滚动,就会再次显示它们 目前,我使用ScrollViewer的SizeChanged事件来检测宽度是否已更改,以及ItemsControl的任何项目是否不可见,因此需要滚动。(见帖
ItemsControl
创建列表,并使其能够通过鼠标滚轮水平滚动,但还添加了两个按钮(左和右)来替换常用的滚动条(因为滚动条会与外观冲突,在这种情况下会过大)
如果列表中没有足够的项目,或者控件的宽度足以显示所有项目,我想折叠按钮,当然,只要需要滚动,就会再次显示它们
目前,我使用ScrollViewer
的SizeChanged
事件来检测宽度是否已更改,以及ItemsControl
的任何项目是否不可见,因此需要滚动。(见帖子底部的C代码。)
我的问题是,只要我用鼠标敲击窗口的边缘来改变大小并以此方式调整大小,它就可以正常工作,但一旦窗口大小按程序更改,或者双击窗口标题使其全屏显示(或使用最大化/最小化按钮),它就无法正常工作
这是我的用户控件:
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<dx:SimpleButton x:Name="scroll_left_button" Grid.Column="0" Content="←"/>
<Border Background="#FF00ACDC" Grid.Column="1" BorderThickness="0">
<ItemsControl x:Name="items_control" w3ClientUi:ScrollViewerHelper.UseHorizontalScrolling="True"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer HorizontalScrollBarVisibility="Hidden">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- dummy template -->
<StackPanel.ToolTip>
<TextBlock Text="{Binding Name}"/>
</StackPanel.ToolTip>
<panda:PndLabel Padding="0 10 2 10" Content="{Binding Number}" FontSize="16" FontWeight="Normal"
Foreground="White" Margin="0 0 2 0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- ItemsSource is set in Code -->
</ItemsControl>
</Border>
<dx:SimpleButton Grid.Column="2" x:Name="scroll_right_button" Content="→"/>
</Grid>
因此,在周末带着全新的想法回来后,我发现,在我的情况下,处理
SizeChanged
事件是错误的方法,因为我真正需要知道的是ItemsControl
中是否有任何项需要滚动,以及数字是否已更改
在我的问题中,我已经检查了ScrollViewer
的ScrollableWidth
属性。它显示了有多少项不可见,需要滚动,因此检查它是否已更改以及它的新值是否大于零就足够了
ScrollableWidth
是一个dependencProperty
,因此我考虑绑定到它并监听更改的事件
因此,我首先在我的UserControl
// Dependency Property is Private since I only need it internally
private static readonly DependencyProperty scrollable_width_property =
DependencyProperty.Register(nameof(scrollable_width), typeof(double),
typeof(MyUserControl),
new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = false, PropertyChangedCallback = property_changed_callback });
// Wrapper only has get because ScrollableWidth is read only anyway
private double scrollable_width => (double)GetValue(scrollable_width_property);
// Listening to the change
private static void property_changed_callback(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
var o = dpo as MyUserControl;
o?.SetButtonVisibility((double)args.NewValue > 0);
}
我删除了scroll\u viewer.SizeChanged
事件,而是在我的用户控件上创建了一个新的公共方法来更改按钮的可见性
public void SetButtonVisibility(bool visible)
{
if (scroll_viewer == null) return;
if (visible)
{
scroll_left_button.Visibility = Visibility.Visible;
scroll_right_button.Visibility = Visibility.Visible;
}
else
{
scroll_left_button.Visibility = Visibility.Collapsed;
scroll_right_button.Visibility = Visibility.Collapsed;
}
}
最后要做的是实际绑定。
在获得实际的ScrollViewer
后,我在ItemsControl
的Loaded
事件中执行一次
var binding = new Binding(nameof(ScrollViewer.ScrollableWidth))
{
Source = scroll_viewer
};
SetBinding(scrollable_width_property, binding);
现在,无论何时ItemControl
需要滚动(或不需要滚动),按钮的可见性都将改变,而不管大小如何变化。现在,当使用窗口标题中的最大化/最小化按钮时,它也可以工作。
它可能不是最好的实现,因为它可能更好地在xaml中使用样式触发器,而不是SetButtonVisibility
方法,但它完成了任务
编辑:
在我的例子中,我还必须添加一个SetButtonVisibility(scroll_viewer.ScrollableWidth>0)
到ItemsContorol
的LoadedEvent
,因为在启动时不会触发回调
var binding = new Binding(nameof(ScrollViewer.ScrollableWidth))
{
Source = scroll_viewer
};
SetBinding(scrollable_width_property, binding);