Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 更改自定义按钮WPF上的笔划和填充_C#_Wpf_Xaml - Fatal编程技术网

C# 更改自定义按钮WPF上的笔划和填充

C# 更改自定义按钮WPF上的笔划和填充,c#,wpf,xaml,C#,Wpf,Xaml,我在一个用C#编写的WPF应用程序中使用多边形和矩形为come media player控件创建了一个模板。我有三个按钮的“状态” Idle = stroke=Black; Fill=Black MouseOver = stroke=White; Fill=Black MouseDown/Disabled = Stroke=black; fill=White 我有前两个工作,但我不能得到最后一个。到目前为止,我有以下代码: <Button Grid.Column="2" Vertical

我在一个用C#编写的WPF应用程序中使用多边形和矩形为come media player控件创建了一个模板。我有三个按钮的“状态”

Idle = stroke=Black; Fill=Black
MouseOver = stroke=White; Fill=Black
MouseDown/Disabled = Stroke=black; fill=White
我有前两个工作,但我不能得到最后一个。到目前为止,我有以下代码:

<Button Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding PlayCommand}" >
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Canvas Height="24" Width="18">
                <Polygon x:Name="play" Points="2,0 18,9 2,18" Fill="Black" Canvas.Top="2"/>
            </Canvas>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="play" Property="Stroke" Value="White"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="False">
                    <Setter TargetName="play" Property="Stroke" Value="Black"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>
ViewModel实现INotifyPropertyChanged

 public bool IsPlaying
 {
     get {return _isPlaying; }
     private set
     {
         if (value != _isPlaying)
         {
             _isPlaying = value;
             OnPropertyChanged(new PropertyChangedEventArgs("IsPlaying"));
         }
     }
 }
当我试图构建一个触发器来设置笔划和填充时,即使按钮被禁用,它们似乎也不会被触发。有什么建议吗?提前谢谢

编辑:

App.xaml.cs

private void App_OnStartup(object sender, StartupEventArgs e)
    {
        Configuration config = new Configuration();
        MainWindow main = new MainWindow(config);
        main.Show();
    }
ViewModel构造函数:

public MainWindowViewModel(Configuration config)
    {
        this.config = config;
        _player = new MediaPlayerMock();
        _player.StatusChanged += _player_StatusChanged;
        PlayCommand = new PlayCommand(this);
        StopCommand = new StopCommand(this);

    }

    public ICommand PlayCommand { get; set; }
    public ICommand StopCommand { get; set; }

当视图模型的
isplay
属性更改时,应触发
CanExecuteChanged
事件:

public class PlayCommand : ICommand
{
    ...
    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _viewModel.Play();
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

或者,您可以在
IsPlaying
上设置数据触发器,而不是在
IsEnabled
上设置触发器:

<DataTrigger Binding="{Binding IsPlaying}" Value="False">
    <Setter ... />                    
</DataTrigger>

当视图模型的
显示属性更改时,应触发
CanExecuteChanged
事件:

public class PlayCommand : ICommand
{
    ...
    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _viewModel.Play();
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

或者,您可以在
IsPlaying
上设置数据触发器,而不是在
IsEnabled
上设置触发器:

<DataTrigger Binding="{Binding IsPlaying}" Value="False">
    <Setter ... />                    
</DataTrigger>

在这种情况下也可以使用VisualState管理器。可视状态为您封装了所有这些,并使您能够基于状态更改控件,而不是基于转换更改控件。这是一个(可能很重要的)区别

TL;博士在底部顺便说一句

当使用数据触发器或触发器时,通常您将受益于使用要触发不同样式的属性和事件。但您只能访问这些转换

相反,国家在国家上工作。区别很简单。转换没有关于状态的信息。如果将鼠标移到只读文本框控件上会发生什么情况?对,它启动悬停更改,尽管此处不适用悬停,因为文本框不可编辑。国家可以照顾到这一点,因为它们只有在满足所有条件时才会改变。触发器将在红色虚线上更改,而状态不会更改

除了获得一致的状态而不是转换之外,您还可以获得更多的好处。您还可以访问控件的焦点状态或验证状态,这是依赖项属性提供的机制

要想知道你想要哪一个,你可以看看你想要改变什么以及什么时候改变。如果您希望将鼠标悬停在控件上,而不是在前面不单击鼠标的情况下悬停,那么您需要的是转换。如果您只想对控件的特定结果状态进行可视化编码,请尽可能改用VisualStateManager

TL;DR:触发器和视觉状态不同,表现也不同。您可能需要评估您需要哪一个。视觉状态仅在模板中定义,这可能是使用它们的缺点。您还需要使用故事板,但如果持续时间为零,它们也会立即应用。例如,可以按如下方式创建平面按钮:

<ControlTemplate TargetType="Button">
        <Grid Background="{TemplateBinding Background}" TextBlock.Foreground="{TemplateBinding Foreground}">
            <Rectangle Fill="White" Opacity="0." x:Name="Overlay" />
            <Rectangle Fill="Gray" Opacity="0." x:Name="OverlayDark" />
            <ContentPresenter Margin="{TemplateBinding Padding}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="CommonStates">
                    <VisualState Name="Normal">
                        <VisualState.Storyboard>
                            <Storyboard>
                                <DoubleAnimation To="0.0" Duration="0:0:0.1" Storyboard.TargetName="Overlay"
                                                 Storyboard.TargetProperty="Opacity" />
                            </Storyboard>
                        </VisualState.Storyboard>
                    </VisualState>
                    <VisualState Name="Pressed">
                        <Storyboard>
                            <DoubleAnimation To="0.5" Duration="0:0:0.1" Storyboard.TargetName="OverlayDark"
                                             Storyboard.TargetProperty="Opacity" />
                        </Storyboard>
                    </VisualState>
                    <VisualState Name="MouseOver">
                        <VisualState.Storyboard>
                            <Storyboard>
                                <DoubleAnimation To="0.5" Duration="0:0:0.1" Storyboard.TargetName="Overlay"
                                                 Storyboard.TargetProperty="Opacity" />
                            </Storyboard>
                        </VisualState.Storyboard>
                    </VisualState>
                    <VisualState Name="Disabled">
                        <Storyboard>
                            <DoubleAnimation To="1" Duration="0:0:0.1" Storyboard.TargetName="OverlayDark"
                                             Storyboard.TargetProperty="Opacity" />
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </ControlTemplate>

在这种情况下也可以使用VisualState管理器。可视状态为您封装了所有这些,并使您能够基于状态更改控件,而不是基于转换更改控件。这是一个(可能很重要的)区别

TL;博士在底部顺便说一句

当使用数据触发器或触发器时,通常您将受益于使用要触发不同样式的属性和事件。但您只能访问这些转换

相反,国家在国家上工作。区别很简单。转换没有关于状态的信息。如果将鼠标移到只读文本框控件上会发生什么情况?对,它启动悬停更改,尽管此处不适用悬停,因为文本框不可编辑。国家可以照顾到这一点,因为它们只有在满足所有条件时才会改变。触发器将在红色虚线上更改,而状态不会更改

除了获得一致的状态而不是转换之外,您还可以获得更多的好处。您还可以访问控件的焦点状态或验证状态,这是依赖项属性提供的机制

要想知道你想要哪一个,你可以看看你想要改变什么以及什么时候改变。如果您希望将鼠标悬停在控件上,而不是在前面不单击鼠标的情况下悬停,那么您需要的是转换。如果您只想对控件的特定结果状态进行可视化编码,请尽可能改用VisualStateManager

TL;DR:触发器和视觉状态不同,表现也不同。您可能需要评估您需要哪一个。视觉状态仅在模板中定义,这可能是使用它们的缺点。您还需要使用故事板,但如果持续时间为零,它们也会立即应用。例如,可以按如下方式创建平面按钮:

<ControlTemplate TargetType="Button">
        <Grid Background="{TemplateBinding Background}" TextBlock.Foreground="{TemplateBinding Foreground}">
            <Rectangle Fill="White" Opacity="0." x:Name="Overlay" />
            <Rectangle Fill="Gray" Opacity="0." x:Name="OverlayDark" />
            <ContentPresenter Margin="{TemplateBinding Padding}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="CommonStates">
                    <VisualState Name="Normal">
                        <VisualState.Storyboard>
                            <Storyboard>
                                <DoubleAnimation To="0.0" Duration="0:0:0.1" Storyboard.TargetName="Overlay"
                                                 Storyboard.TargetProperty="Opacity" />
                            </Storyboard>
                        </VisualState.Storyboard>
                    </VisualState>
                    <VisualState Name="Pressed">
                        <Storyboard>
                            <DoubleAnimation To="0.5" Duration="0:0:0.1" Storyboard.TargetName="OverlayDark"
                                             Storyboard.TargetProperty="Opacity" />
                        </Storyboard>
                    </VisualState>
                    <VisualState Name="MouseOver">
                        <VisualState.Storyboard>
                            <Storyboard>
                                <DoubleAnimation To="0.5" Duration="0:0:0.1" Storyboard.TargetName="Overlay"
                                                 Storyboard.TargetProperty="Opacity" />
                            </Storyboard>
                        </VisualState.Storyboard>
                    </VisualState>
                    <VisualState Name="Disabled">
                        <Storyboard>
                            <DoubleAnimation To="1" Duration="0:0:0.1" Storyboard.TargetName="OverlayDark"
                                             Storyboard.TargetProperty="Opacity" />
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </ControlTemplate>