如何使用 Prism/WPF/MahApps 隐藏按钮的背景?
How can I hide the background of a button using Prism/WPF/MahApps?
我正在学习 Brian Lagunas 的 PluralSight 教程,介绍如何使用 Prism,因为我仍然想掌握使用 MVVM 的概念。
我有一个看起来不错的按钮,当通过上面的方法启用时 CheckBox
:
然而,当 Button
不再通过 Prism 的委托命令启用时,我会在按钮周围看到一个 window。
当 Button
被禁用时,如何删除那个框?我想改为更改前景以使齿轮图标变为灰色,但暂时决定删除该框。
下面是 StackPanel
和我尝试过的隐藏代码
XAML代码:
<StackPanel HorizontalAlignment="Left" Orientation="Vertical">
<CheckBox Content="CanExecute" IsChecked="{Binding CanExecute}"></CheckBox>
<Button Command="{Binding ClickCommand}" Background="#a9afb8" Height="35" Width="35" BorderThickness="0" ToolTip=" Marks the current work order as complete.">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="#a9afb8"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<iconPacks:Unicons Width="35" Height="35" Kind="Cog" />
</Button>
<TextBlock Text="{Binding Title}"></TextBlock>
</StackPanel>
代码隐藏:
public class ViewAViewModel : BindableBase
{
private string _title = "ViewAVM";
public string Title
{
get { return _title; }
set
{
SetProperty(ref _title, value);
}
}
private bool _canExecute = false;
public bool CanExecute
{
get { return _canExecute; }
set
{
SetProperty(ref _canExecute, value);
ClickCommand.RaiseCanExecuteChanged();
}
}
public DelegateCommand ClickCommand { get; private set; }
public ViewAViewModel()
{
ClickCommand = new DelegateCommand(Click, CanClick);
}
private bool CanClick()
{
return CanExecute;
}
private void Click()
{
Title = "Clicked";
}
}
该问题与 MVVM 无关。 WPF 中的控件具有在 XAML 中定义的视觉和逻辑结构,以及状态和这些状态的触发器,用于在状态更改时更改控件属性。这是在控件模板中定义的。
在 Button
的情况下,有 Pressed、MouseOver 或 Disabled 仅举几例。所有这些状态都有一个视觉表示。比如在Disabled状态下,Background
会变成浅灰色,不透明度会降低。控件模板中的触发器优先于样式中定义的触发器,因此您需要创建自定义控件模板来更改 Disabled 状态的表示。
由于创建自定义控件模板可能很复杂,您应该复制默认控件模板或控件样式并进行调整。请注意,默认模板可能因您使用的库而异。在 MahApps.Metro 的情况下,您可以找到默认按钮样式和模板 here。
您感兴趣的部分是 Disabled 状态的触发器。
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="DisabledVisualElement" Property="Opacity" Value="0.7" />
<Setter TargetName="PART_ContentPresenter" Property="Opacity" Value="0.3" />
</Trigger>
因为您不想更改 Background
,而是 Foreground
,请像下面那样替换 Setter
并将 LightGray
颜色调整为你想拥有
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
</Trigger>
如果你也想改变其他状态,你可以用同样的方法。这是整个样式:
<Style x:Key="MyButtonStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray10}" />
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Controls:ControlsHelper.ContentCharacterCasing" Value="Upper" />
<Setter Property="Controls:ControlsHelper.CornerRadius" Value="3" />
<Setter Property="Controls:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.Focus}" />
<Setter Property="Controls:ControlsHelper.FocusBorderThickness" Value="2" />
<Setter Property="Controls:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.MouseOver}" />
<Setter Property="FontFamily" Value="{DynamicResource MahApps.Fonts.Family.Button}" />
<Setter Property="FontSize" Value="{DynamicResource MahApps.Font.Size.Button}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.ThemeForeground}" />
<Setter Property="MinHeight" Value="25" />
<Setter Property="Padding" Value="5 6" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Grid>
<Controls:ClipBorder x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding Controls:ControlsHelper.CornerRadius}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<Controls:ClipBorder x:Name="DisabledVisualElement"
Background="{DynamicResource MahApps.Brushes.Control.Disabled}"
CornerRadius="{TemplateBinding Controls:ControlsHelper.CornerRadius}"
IsHitTestVisible="False"
Opacity="0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<Controls:ContentControlEx x:Name="PART_ContentPresenter"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentCharacterCasing="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.ContentCharacterCasing)}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
RecognizesAccessKey="{TemplateBinding Controls:ControlsHelper.RecognizesAccessKey}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MahApps.Brushes.Gray8}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.MouseOverBorderBrush), Mode=OneWay}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MahApps.Brushes.Gray7}" />
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.FocusBorderBrush), Mode=OneWay}" />
<Setter TargetName="Border" Property="BorderThickness" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.FocusBorderThickness), Mode=OneWay}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
您可以应用 Style
和控件模板 like below or apply it implicitly:
<Button Style="{StaticResource MyButtonStyle}" ...>
<iconPacks:Unicons Width="35" Height="35" Kind="Cog" />
</Button>
如果想了解更多控件的状态和结构,可以参考MSDN上的文档,例如Button
here。但是,那里的示例可能不完整或有点过时。
我正在学习 Brian Lagunas 的 PluralSight 教程,介绍如何使用 Prism,因为我仍然想掌握使用 MVVM 的概念。
我有一个看起来不错的按钮,当通过上面的方法启用时 CheckBox
:
然而,当 Button
不再通过 Prism 的委托命令启用时,我会在按钮周围看到一个 window。
当 Button
被禁用时,如何删除那个框?我想改为更改前景以使齿轮图标变为灰色,但暂时决定删除该框。
下面是 StackPanel
和我尝试过的隐藏代码
XAML代码:
<StackPanel HorizontalAlignment="Left" Orientation="Vertical">
<CheckBox Content="CanExecute" IsChecked="{Binding CanExecute}"></CheckBox>
<Button Command="{Binding ClickCommand}" Background="#a9afb8" Height="35" Width="35" BorderThickness="0" ToolTip=" Marks the current work order as complete.">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="#a9afb8"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<iconPacks:Unicons Width="35" Height="35" Kind="Cog" />
</Button>
<TextBlock Text="{Binding Title}"></TextBlock>
</StackPanel>
代码隐藏:
public class ViewAViewModel : BindableBase
{
private string _title = "ViewAVM";
public string Title
{
get { return _title; }
set
{
SetProperty(ref _title, value);
}
}
private bool _canExecute = false;
public bool CanExecute
{
get { return _canExecute; }
set
{
SetProperty(ref _canExecute, value);
ClickCommand.RaiseCanExecuteChanged();
}
}
public DelegateCommand ClickCommand { get; private set; }
public ViewAViewModel()
{
ClickCommand = new DelegateCommand(Click, CanClick);
}
private bool CanClick()
{
return CanExecute;
}
private void Click()
{
Title = "Clicked";
}
}
该问题与 MVVM 无关。 WPF 中的控件具有在 XAML 中定义的视觉和逻辑结构,以及状态和这些状态的触发器,用于在状态更改时更改控件属性。这是在控件模板中定义的。
在 Button
的情况下,有 Pressed、MouseOver 或 Disabled 仅举几例。所有这些状态都有一个视觉表示。比如在Disabled状态下,Background
会变成浅灰色,不透明度会降低。控件模板中的触发器优先于样式中定义的触发器,因此您需要创建自定义控件模板来更改 Disabled 状态的表示。
由于创建自定义控件模板可能很复杂,您应该复制默认控件模板或控件样式并进行调整。请注意,默认模板可能因您使用的库而异。在 MahApps.Metro 的情况下,您可以找到默认按钮样式和模板 here。
您感兴趣的部分是 Disabled 状态的触发器。
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="DisabledVisualElement" Property="Opacity" Value="0.7" />
<Setter TargetName="PART_ContentPresenter" Property="Opacity" Value="0.3" />
</Trigger>
因为您不想更改 Background
,而是 Foreground
,请像下面那样替换 Setter
并将 LightGray
颜色调整为你想拥有
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
</Trigger>
如果你也想改变其他状态,你可以用同样的方法。这是整个样式:
<Style x:Key="MyButtonStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray10}" />
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Controls:ControlsHelper.ContentCharacterCasing" Value="Upper" />
<Setter Property="Controls:ControlsHelper.CornerRadius" Value="3" />
<Setter Property="Controls:ControlsHelper.FocusBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.Focus}" />
<Setter Property="Controls:ControlsHelper.FocusBorderThickness" Value="2" />
<Setter Property="Controls:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource MahApps.Brushes.Button.Border.MouseOver}" />
<Setter Property="FontFamily" Value="{DynamicResource MahApps.Fonts.Family.Button}" />
<Setter Property="FontSize" Value="{DynamicResource MahApps.Font.Size.Button}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.ThemeForeground}" />
<Setter Property="MinHeight" Value="25" />
<Setter Property="Padding" Value="5 6" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Grid>
<Controls:ClipBorder x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding Controls:ControlsHelper.CornerRadius}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<Controls:ClipBorder x:Name="DisabledVisualElement"
Background="{DynamicResource MahApps.Brushes.Control.Disabled}"
CornerRadius="{TemplateBinding Controls:ControlsHelper.CornerRadius}"
IsHitTestVisible="False"
Opacity="0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<Controls:ContentControlEx x:Name="PART_ContentPresenter"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentCharacterCasing="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.ContentCharacterCasing)}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
RecognizesAccessKey="{TemplateBinding Controls:ControlsHelper.RecognizesAccessKey}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MahApps.Brushes.Gray8}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.MouseOverBorderBrush), Mode=OneWay}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MahApps.Brushes.Gray7}" />
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.FocusBorderBrush), Mode=OneWay}" />
<Setter TargetName="Border" Property="BorderThickness" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ControlsHelper.FocusBorderThickness), Mode=OneWay}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
您可以应用 Style
和控件模板 like below or apply it implicitly:
<Button Style="{StaticResource MyButtonStyle}" ...>
<iconPacks:Unicons Width="35" Height="35" Kind="Cog" />
</Button>
如果想了解更多控件的状态和结构,可以参考MSDN上的文档,例如Button
here。但是,那里的示例可能不完整或有点过时。