我正在尝试在 WPF 中实现一种单行选项卡控件,它在包含选项卡的区域的左侧和右侧显示滚动按钮。这些选项卡在自定义控件中实现。只有当窗口太小而无法显示所有选项卡时,才应显示滚动按钮。 通过拖动边框调整窗口大小时,一切都按预期进行。 但是当窗口最大化然后恢复时,右滚动按钮保持隐藏状态。
只有当右滚动按钮的 Visibility
属性数据绑定(bind)到在自定义控件的 Measure pass 中更新的自定义控件的依赖属性时,问题似乎才会出现。
我的问题是:我在这里使用 WPF 是否正确,或者是否需要以不同的方式完成某些事情? (请注意:我需要使用数据绑定(bind)和自定义控件;因此请避免建议采取完全不同的方法的答案。)
这是一个说明问题的小示例程序:
当宽度较小时:
当宽度较大时:
这些是示例程序的文件:
主窗口.xaml:
<Window x:Class="GridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gridTest="clr-namespace:GridTest"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="theGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="btnScrollLeft" Content="<" Grid.Row="0" Grid.Column="0" Width="30"/>
<gridTest:MyCustomControl x:Name="cust" Grid.Row="0" Grid.Column="1"/>
<Button x:Name="btnScrollRight" Content=">" Grid.Row="0" Grid.Column="2" Width="30"
Visibility="{Binding ElementName=cust, Path=ShowButton}"/>
<TextBox Text="The content goes here..." Grid.Row="1" Grid.ColumnSpan="3"
Background="LightGreen" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<Button x:Name="btnRedraw" Grid.Row="1" Grid.Column="1" Content="Redraw" VerticalAlignment="Bottom"
HorizontalAlignment="Center" Click="btnRedraw_Click" />
</Grid>
</Window>
主窗口.xaml.cs:
using System.Windows;
namespace GridTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnRedraw_Click(object sender, RoutedEventArgs e)
{
theGrid.InvalidateMeasure();
}
}
}
我的自定义控件.cs:
using System;
using System.Windows;
using System.Windows.Controls;
namespace GridTest
{
public class MyCustomControl : Control
{
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public Visibility ShowButton
{
get { return (Visibility)GetValue(ShowButtonProperty); }
set { SetValue(ShowButtonProperty, value); }
}
// Using a DependencyProperty as the backing store for ShowButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ShowButtonProperty =
DependencyProperty.Register("ShowButton", typeof(Visibility), typeof(MyCustomControl), new UIPropertyMetadata(Visibility.Visible));
protected override Size MeasureOverride(Size constraint)
{
if (constraint.Width > 800)
{
ShowButton = Visibility.Collapsed;
}
else
{
ShowButton = Visibility.Visible;
}
double width = Math.Min(2000.0, constraint.Width);
double height = Math.Min(50.0, constraint.Height);
return new Size(width, height);
}
}
}
通用.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GridTest">
<Style TargetType="{x:Type local:MyCustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<Border Background="LightCyan">
<TextBlock VerticalAlignment="Center" TextAlignment="Center">Custom Control</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
问题可以重现如下:
- 确保窗口很小,以便可以看到右侧的滚动按钮。
- 现在最大化窗口。 => 右滚动按钮应该变得不可见。
- 现在将窗口恢复到原来的大小。 => 右滚动按钮应该再次可见。 (问题是:右滚动按钮仍然不可见。)
编辑:仅供引用:我可以使用 VS2010+.NET4.0 和 VS2013+.NET4.51 重现该问题。
最佳答案
您需要将 ShowButton
可见性更改分派(dispatch)回分派(dispatch)队列才能正常工作(为应用程序提供渲染和顺序所需的时间)而不是直接在 MeasureOverride
方法。
假设我将您的 MeasureOverride
更改为
protected override Size MeasureOverride(Size constraint) {
if (constraint.Width > 800) {
Application.Current.Dispatcher.BeginInvoke(
new Action(() => ShowButton = Visibility.Collapsed));
} else {
Application.Current.Dispatcher.BeginInvoke(
new Action(() => ShowButton = Visibility.Visible));
}
double width = Math.Min(2000.0, constraint.Width);
double height = Math.Min(50.0, constraint.Height);
return new Size(width, height);
}
你可以看到它工作正常。
使用您发布的原始代码,您可以看到,即使您最大化 Window
,右侧的 Button
也会隐藏,但实际上不会 Collapsed
就像您将其设置为那样,这又是由于控件未获得新大小的相同原因。
此外,在恢复并使 Button
保持隐藏状态后,如果您通过拖动它的大小来调整 Window
的大小,您可以看到该按钮变为 Visible
再次。
通过调度 Visibility
更改,如果您在 MeasureOverride
函数中有一个断点,您可以看到它被调用了两次(一次用于 Window
由于 Button
被隐藏/显示而导致的尺寸变化和第二个尺寸变化)本质上是在最大化/恢复窗口时,从而产生正确的尺寸计算和您想要的输出。
关于c# - 恢复最大化窗口时,网格列大小未正确重新计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19541821/