Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.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,我在WPF应用程序中有一个无铬按钮,它使用下面的XAML样式: 然而,有两件事我正试图用它来做 我希望显示的图像是两个图像之一,具体取决于按钮所在模板的datacontext中的绑定属性。该属性是布尔值。如果为假,则显示一个图像,如果为真,则显示另一个图像 我想显示的图像改变时,鼠标悬停在按钮上,并将显示的图像时,上述绑定属性为真 我试过几种方法,但似乎都不管用。我尝试了一个绑定值如下的转换器: <x:ArrayExtension x:Key="ThumbsDown" Ty

我在WPF应用程序中有一个无铬按钮,它使用下面的XAML样式: 然而,有两件事我正试图用它来做

  • 我希望显示的图像是两个图像之一,具体取决于按钮所在模板的datacontext中的绑定属性。该属性是布尔值。如果为假,则显示一个图像,如果为真,则显示另一个图像
  • 我想显示的图像改变时,鼠标悬停在按钮上,并将显示的图像时,上述绑定属性为真
  • 我试过几种方法,但似乎都不管用。我尝试了一个绑定值如下的转换器:

            <x:ArrayExtension x:Key="ThumbsDown" Type="BitmapImage">
                <BitmapImage UriSource="/Elpis;component/Images/thumbDown.png" />
                <BitmapImage UriSource="/Elpis;component/Images/thumbBan.png" />
            </x:ArrayExtension>
    
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var data = (object[])parameter;
    
                if (data.Length != 2 || value == null || value.GetType() != typeof(bool))
                    return data[0];
    
                if(!((bool)value))
                    return data[0];
                else
                    return data[1];
            }
    
    <Button Name="btnThumbDown" Grid.Column="1" Style="{StaticResource NoChromeButton}" 
                                                VerticalAlignment="Center" 
                                                HorizontalAlignment="Center" 
                                                Background="Transparent"
                                                Click="btnThumbDown_Click">
                                    <Image  Width="32" Height="32" Margin="2" 
                                            Source="{Binding Banned, 
                                                    Converter={StaticResource binaryChooser}, 
                                                    ConverterParameter={StaticResource ThumbsDown}}"/>
                                </Button>
    
    <Style TargetType="SomeNamespace:ImageButton">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Padding" Value="1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type SomeNamespace:ImageButton}">
                    <Grid x:Name="Chrome" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Image x:Name="ButtonImage" Grid.Column="0"
                            Source="{Binding ActiveImageUri, RelativeSource={RelativeSource TemplatedParent}}" />
                        <ContentPresenter Grid.Column="1"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <!-- The "active" image should be shown when IsMouseOver == True OR the bound boolean is true,
                            so if you invert that you could say that the "inactive" image should be shown
                            when IsMouseOver == false AND the bound boolean is false, which is what this trigger does -->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="False" />
                                <Condition Property="IsActive" Value="False" />
                            </MultiTrigger.Conditions>
                            <MultiTrigger.Setters>
                                <Setter TargetName="ButtonImage" Property="Source"
                                    Value="{Binding InactiveImageUri, RelativeSource={RelativeSource TemplatedParent}}" />
                            </MultiTrigger.Setters>
                        </MultiTrigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Opacity" Value="0.75" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    
    公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
    {
    变量数据=(对象[])参数;
    if(data.Length!=2 | | value==null | | value.GetType()!=typeof(bool))
    返回数据[0];
    如果(!((布尔)值))
    返回数据[0];
    其他的
    返回数据[1];
    }
    
    但这会导致两个问题。我对悬停图像所做的任何操作都不再有效,设计师抛出了一个异常

    下面的不透明度触发器可以启动,因为我现在真的只需要悬停

    有没有关于如何使其正常工作的想法

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Style x:Key="NoChromeButton" TargetType="{x:Type ButtonBase}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ButtonBase}">
                        <Grid x:Name="Chrome" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                              Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" 
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Opacity" Value="0.75"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="False">
                                <Setter Property="Opacity" Value="1.0"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    

    您必须做几件事:

  • 为要显示的每个图像设置
    ImageBrush
    资源
  • 为具有内置
    样式的按钮创建
    控制模板
    ,鼠标悬停在
    触发器上
  • 通过将
    Background
    属性从点1绑定到
    ImageBrush
    资源之一,在
    按钮上设置图像
  • 将鼠标悬停在
    Trigger
    上,将
    Background
    属性更改为另一个
    ImageBrush
    资源
  • 请参阅下面的代码以获得一个简单的示例(您必须使用自己的图像来代替“向上”和“向下”)

    
    
    这里的关键是在
    边框的
    样式上实现触发器,而不是直接在
    按钮上实现触发器。当尝试从应用于
    按钮的
    样式设置
    边框的属性时,我无法使其工作。您还可以将
    边框
    替换为
    矩形
    ,或将任何其他
    内容控件
    替换为
    背景
    属性


    从这里开始,根据您认为适合您的应用程序进行自定义。

    您必须做几件事:

  • 为要显示的每个图像设置
    ImageBrush
    资源
  • 为具有内置
    样式的按钮创建
    控制模板
    ,鼠标悬停在
    触发器上
  • 通过将
    Background
    属性从点1绑定到
    ImageBrush
    资源之一,在
    按钮上设置图像
  • 将鼠标悬停在
    Trigger
    上,将
    Background
    属性更改为另一个
    ImageBrush
    资源
  • 请参阅下面的代码以获得一个简单的示例(您必须使用自己的图像来代替“向上”和“向下”)

    
    
    这里的关键是在
    边框的
    样式上实现触发器,而不是直接在
    按钮上实现触发器。当尝试从应用于
    按钮的
    样式设置
    边框的属性时,我无法使其工作。您还可以将
    边框
    替换为
    矩形
    ,或将任何其他
    内容控件
    替换为
    背景
    属性


    从这里开始,根据您认为适合您的应用程序进行自定义。

    我将通过向按钮的
    控件模板
    添加
    图像
    控件来解决这个问题,然后创建一个
    多数据触发器
    ,其中一个条件用于
    IsMouseOver
    ,另一个条件用于要绑定的布尔属性。然后,触发器在激活时设置图像的源

    下面是实现这一点的样式。我假设按钮有一个包含布尔属性的DataContext,布尔属性称为MyBoolean

    <Style x:Key="NoChromeButton" TargetType="{x:Type ButtonBase}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <!-- I assume that the button has a DataContext with a boolean property called MyBoolean -->
                <ControlTemplate TargetType="{x:Type ButtonBase}">
                    <Grid x:Name="Chrome" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                        <!-- Not sure about what the button should look like, so I made it an image to the left
                                and the button's content to the right -->
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Image x:Name="ButtonImage" Grid.Column="0" Source="/Elpis;component/Images/thumbBan.png" />
                        <ContentPresenter Grid.Column="1"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                        Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" 
                                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Grid>
                <ControlTemplate.Triggers>
                    <!-- As I understand it, ThumbBan should be shown when IsMouseOver == True OR the bound boolean is true,
                            so if you invert that you could say that the ThumbDown image should be shown
                            when IsMouseOver == false AND the bound boolean is false, which is what this trigger does -->
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding IsMouseOver, ElementName=Chrome}" Value="False" />
                                <Condition Binding="{Binding MyBoolean}" Value="False" />
                            </MultiDataTrigger.Conditions>
                            <MultiDataTrigger.Setters>
                                <Setter TargetName="ButtonImage" Property="Source" Value="/Elpis;component/Images/thumbDown.png" />
                            </MultiDataTrigger.Setters>
                        </MultiDataTrigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Opacity" Value="0.75"/>
                    </Trigger>
                    <!-- The trigger that sets opacity to 1 for IsMouseOver false is not needed, since 1 is the 
                            default and will be the opacity as long as the trigger above is not active -->
                </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    然后,可以以下列方式使用此类:

    <SomeNamespace:ImageButton Height="23" Width="100" Content="Button 1"
        ActiveImageUri="/Elpis;component/Images/thumbBan.png"
        InactiveImageUri="/Elpis;component/Images/thumbDown.png"
        IsActive="{Binding MyBoolean}" />
    
    <SomeNamespace:ImageButton Height="23" Width="100" Content="Button 2"
        ActiveImageUri="/Elpis;component/Images/someOtherImage.png"
        InactiveImageUri="/Elpis;component/Images/yetAnotherImage.png"
        IsActive="{Binding SomeOtherBooleanProperty}" />
    
    
    
    然后可以修改控制模板
    <SomeNamespace:ImageButton Height="23" Width="100" Content="Button 1"
        ActiveImageUri="/Elpis;component/Images/thumbBan.png"
        InactiveImageUri="/Elpis;component/Images/thumbDown.png"
        IsActive="{Binding MyBoolean}" />
    
    <SomeNamespace:ImageButton Height="23" Width="100" Content="Button 2"
        ActiveImageUri="/Elpis;component/Images/someOtherImage.png"
        InactiveImageUri="/Elpis;component/Images/yetAnotherImage.png"
        IsActive="{Binding SomeOtherBooleanProperty}" />
    
    <Style TargetType="SomeNamespace:ImageButton">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Padding" Value="1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type SomeNamespace:ImageButton}">
                    <Grid x:Name="Chrome" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Image x:Name="ButtonImage" Grid.Column="0"
                            Source="{Binding ActiveImageUri, RelativeSource={RelativeSource TemplatedParent}}" />
                        <ContentPresenter Grid.Column="1"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <!-- The "active" image should be shown when IsMouseOver == True OR the bound boolean is true,
                            so if you invert that you could say that the "inactive" image should be shown
                            when IsMouseOver == false AND the bound boolean is false, which is what this trigger does -->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="False" />
                                <Condition Property="IsActive" Value="False" />
                            </MultiTrigger.Conditions>
                            <MultiTrigger.Setters>
                                <Setter TargetName="ButtonImage" Property="Source"
                                    Value="{Binding InactiveImageUri, RelativeSource={RelativeSource TemplatedParent}}" />
                            </MultiTrigger.Setters>
                        </MultiTrigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Opacity" Value="0.75" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>