WPF Material Design文本框透显幻灯片切换问题及解决办法咨询
我明白你遇到的这个透显和虚线框交叉显示的问题,这在Material Design Transitioner切换时确实偶尔会碰到——主要是因为TextBox的焦点视觉样式(那个虚线框)在过渡动画期间没有正确隐藏,再加上WPF渲染层的特性,导致前后幻灯片的元素互相透显。这里有几个可行的解决办法,按从简单到复杂排序:
方法1:直接移除TextBox的焦点虚线框
这是最直接的方案,既然你已经猜测问题出在这个虚线框上,我们可以通过设置FocusVisualStyle="{x:Null}"来完全移除它。修改你的TextBox代码如下:
<!-- 第一页的TextBox --> <TextBox materialDesign:HintAssist.Hint="Type your first text here!" Margin="10" FocusVisualStyle="{x:Null}"/> <!-- 第二页的TextBox --> <TextBox materialDesign:HintAssist.Hint="Type your second text here!" Margin="15" FocusVisualStyle="{x:Null}"/>
这样切换幻灯片时,就不会再出现焦点虚线框互相透显的情况了。
方法2:给幻灯片容器添加背景色
如果移除焦点样式后仍有轻微透显,那大概率是因为幻灯片的容器(StackPanel)没有设置背景,WPF会默认将其视为透明层,导致后面的元素“透出来”。我们可以给每个TransitionerSlide里的StackPanel设置和窗口一致的背景色:
<!-- 第一页的StackPanel --> <StackPanel HorizontalAlignment="Center" Background="{DynamicResource MaterialDesignPaper}"> <!-- 第二页的StackPanel --> <StackPanel HorizontalAlignment="Center" Background="{DynamicResource MaterialDesignPaper}">
MaterialDesignPaper是Material Design内置的主题背景色,和你的应用风格会保持一致,这样当前幻灯片的背景就会完全覆盖后面的内容。
方法3:通过动画控制非当前幻灯片的透明度(进阶方案)
如果你需要保留焦点样式,同时解决透显问题,可以给Transitioner添加动画,在切换过程中把非当前幻灯片的TextBox透明度设为0,切换完成后再恢复。
首先,给两个TextBox命名,并给Transitioner添加触发动画:
<Grid> <materialDesign:Transitioner x:Name="MainTransitioner" SelectedIndex="0"> <materialDesign:Transitioner.Triggers> <EventTrigger RoutedEvent="materialDesign:Transitioner.SelectedIndexChanged"> <BeginStoryboard> <Storyboard> <!-- 控制第一页TextBox的透明度 --> <DoubleAnimation Storyboard.TargetName="FirstPageTextBox" Storyboard.TargetProperty="Opacity" To="{Binding ElementName=MainTransitioner, Path=SelectedIndex, Converter={StaticResource IndexToOpacityConverter}, ConverterParameter=0}" Duration="0:0:0.2"/> <!-- 控制第二页TextBox的透明度 --> <DoubleAnimation Storyboard.TargetName="SecondPageTextBox" Storyboard.TargetProperty="Opacity" To="{Binding ElementName=MainTransitioner, Path=SelectedIndex, Converter={StaticResource IndexToOpacityConverter}, ConverterParameter=1}" Duration="0:0:0.2"/> </Storyboard> </BeginStoryboard> </EventTrigger> </materialDesign:Transitioner.Triggers> <materialDesign:TransitionerSlide> <StackPanel HorizontalAlignment="Center" Background="{DynamicResource MaterialDesignPaper}"> <TextBlock Text="Hello, this is my first page!" Margin="10"/> <TextBox x:Name="FirstPageTextBox" materialDesign:HintAssist.Hint="Type your first text here!" Margin="10"/> <Button Command="{x:Static materialDesign:Transitioner.MoveNextCommand}" Content=">" HorizontalAlignment="Center" Margin="10"/> </StackPanel> </materialDesign:TransitionerSlide> <materialDesign:TransitionerSlide> <StackPanel HorizontalAlignment="Center" Background="{DynamicResource MaterialDesignPaper}"> <TextBlock Text="Hello, this is my 2nd page!" Margin="15"/> <TextBox x:Name="SecondPageTextBox" materialDesign:HintAssist.Hint="Type your second text here!" Margin="15"/> <Button Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}" Content="<" HorizontalAlignment="Center" Margin="15"/> </StackPanel> </materialDesign:TransitionerSlide> </materialDesign:Transitioner> </Grid>
然后需要创建一个转换器IndexToOpacityConverter,用来根据当前选中的索引判断是否显示TextBox:
using System; using System.Globalization; using System.Windows.Data; namespace YourNamespace { public class IndexToOpacityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { int currentIndex = (int)value; int targetIndex = int.Parse(parameter.ToString()); // 当前索引匹配目标索引时显示(透明度1),否则隐藏(透明度0) return currentIndex == targetIndex ? 1.0 : 0.0; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }
最后在窗口的资源中声明这个转换器:
<Window.Resources> <local:IndexToOpacityConverter x:Key="IndexToOpacityConverter"/> </Window.Resources>
这个方案会在切换动画期间自动隐藏非当前页的TextBox,完美解决透显问题,同时保留焦点样式。
内容的提问来源于stack exchange,提问作者Samuel Cabrera

