以下是XAML的片段。任何人都可以解释为什么即使VisualState Name=”Determinate”
不包含任何故事板,元素(在本例中)也会改变其正常的视觉外观?
如果我删除该行('VisualState Name =“确定”/'),则ProgressBar会将bot恢复为其原始外观。是因为如果它不处于不确定状态,它必须处于确定状态,这是由DEFAULT功能支持的吗?
我真正说的是,'VisualState Name =“确定”/ - 即使它被认为通过评论无所作为 - 确实会产生影响。如果我们注释掉视觉状态线并将鼠标悬停在右侧饼图上,就可以看到这种影响。在这种情况下,饼图将不会恢复到其“正常”外观。这是为什么 ?现场发生了什么?
<Application x:Class="WindowsApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WindowsApplication1"
StartupUri="Window1.xaml">
<Application.Resources>
<LinearGradientBrush x:Key="foregroundBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="LightGreen"/>
<GradientStop Offset="1" Color="DarkGreen"/>
</LinearGradientBrush>
<ControlTemplate x:Key="progressPie" TargetType="{x:Type ProgressBar}">
<!-- Resources -->
<ControlTemplate.Resources>
<local:ValueMinMaxToPointConverter x:Key="converter1"/>
<local:ValueMinMaxToIsLargeArcConverter x:Key="converter2"/>
</ControlTemplate.Resources>
<!-- Visual Tree -->
<Viewbox>
<!-- Visual State Groups -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Determinate"/>
<!-- Nothing to do for this state -->
<VisualState Name="Indeterminate">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="pie" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="backgroundNormal" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="backgroundIndeterminate" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Width="20" Height="20">
<Ellipse x:Name="backgroundIndeterminate" Opacity="0" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}" Width="20" Height="20">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="Yellow"/>
<GradientStop Offset="1" Color="Brown"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="backgroundNormal" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}" Width="20" Height="20" Fill="{TemplateBinding Background}"/>
<Path x:Name="pie" Fill="{TemplateBinding Foreground}">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="10,10" IsClosed="True">
<LineSegment Point="10,0"/>
<ArcSegment Size="10,10" SweepDirection="Clockwise">
<ArcSegment.Point>
<MultiBinding Converter="{StaticResource converter1}">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
</MultiBinding>
</ArcSegment.Point>
<ArcSegment.IsLargeArc>
<MultiBinding Converter="{StaticResource converter2}">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
</MultiBinding>
</ArcSegment.IsLargeArc>
</ArcSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Viewbox>
<!-- Only one Trigger -->
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="pie" Property="Fill">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="Gray"/>
<GradientStop Offset="1" Color="White"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Application.Resources>
</Application>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WindowsApplication1.Window1">
<StackPanel Orientation="Horizontal">
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="0" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="10" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="50" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="75" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="100" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="10" IsEnabled="False" Template="{StaticResource progressPie}" Margin="10"/>
<ProgressBar Foreground="{StaticResource foregroundBrush}" Width="100"
Height="100" Value="10" IsIndeterminate="True" Template="{StaticResource progressPie}" Margin="10" MouseEnter="RoutedEventHandler"/>
</StackPanel>
</Window>
namespace WindowsApplication1
{
public class ValueMinMaxToIsLargeArcConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
CultureInfo culture)
{
double value = (double)values[0];
double minimum = (double)values[1];
double maximum = (double)values[2];
// Only return true if the value is 50% of the range or greater
return ((value * 2) >= (maximum - minimum));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
public class ValueMinMaxToPointConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
CultureInfo culture)
{
double value = (double)values[0];
double minimum = (double)values[1];
double maximum = (double)values[2];
// Convert the value to one between 0 and 360
double current = (value / (maximum - minimum)) * 360;
// Adjust the finished state so the ArcSegment gets drawn as a whole circle
if (current == 360)
current = 359.999;
// Shift by 90 degrees so 0 starts at the top of the circle
current = current - 90;
// Convert the angle to radians
current = current * 0.017453292519943295;
// Calculate the circle's point
double x = 10 + 10 * Math.Cos(current);
double y = 10 + 10 * Math.Sin(current);
return new Point(x, y);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
namespace WindowsApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public void RoutedEventHandler(object sender, RoutedEventArgs e)
{
int a = 0;
((ProgressBar)sender).IsIndeterminate = false;
}
}
}
答案 0 :(得分:0)
是因为如果它不处于不确定状态,它必须处于确定状态,DEFAULT功能支持该状态吗?
是的,这是正确的。如果查看控件模板的内容,您应该看到它已配置为确定状态 - 这是它的默认值。更改为“Indeterminate”状态会应用其故事板,然后更改回“Determinate”会反转该故事板的效果。
如果我们注释掉视觉状态行并将鼠标悬停在右侧饼图上,就可以看到这种影响。在这种情况下,饼图将不会恢复到其“正常”外观。这是为什么?场景背后会发生什么?
我不确定,但我的猜测是,当控件试图进入“确定”状态时,运行时会看到没有这样的状态,并抛出异常(您可以在Visual Studio中检查“输出”窗口)确认这一点)。在任何情况下,这种行为都不足为奇 - 如果您希望控件正常运行,您需要在其控件模板中包含所有named parts and visual states。