WPF视觉状态

时间:2014-05-10 17:12:52

标签: wpf visualstatemanager

以下是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;
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

  

是因为如果它不处于不确定状态,它必须处于确定状态,DEFAULT功能支持该状态吗?

是的,这是正确的。如果查看控件模板的内容,您应该看到它已配置为确定状态 - 这是它的默认值。更改为“Indeterminate”状态会应用其故事板,然后更改回“Determinate”会反转该故事板的效果。

  

如果我们注释掉视觉状态行并将鼠标悬停在右侧饼图上,就可以看到这种影响。在这种情况下,饼图将不会恢复到其“正常”外观。这是为什么?场景背后会发生什么?

我不确定,但我的猜测是,当控件试图进入“确定”状态时,运行时会看到没有这样的状态,并抛出异常(您可以在Visual Studio中检查“输出”窗口)确认这一点)。在任何情况下,这种行为都不足为奇 - 如果您希望控件正常运行,您需要在其控件模板中包含所有named parts and visual states