如何通过继承Button与XAML样式实现随IsExecuting切换图片的自定义按钮
解决方法
1. 先确认ViewModelBase的INotifyPropertyChanged实现
你的AsyncCommand继承了ViewModelBase,得确保这个基类已经正确实现了INotifyPropertyChanged接口——不然IsExecuting的属性变更没法通知到UI,后续的绑定都白搭。
2. 自定义Button类(极简版)
不用加任何额外属性,直接继承Button就行,主要是给样式一个明确的目标类型:
public class CustomButton : Button { // 啥都不用写,就当个空壳子 }
3. 核心:写XAML样式实现图片切换
用DataTrigger直接绑定按钮的Command.IsExecuting属性,根据状态切换显示的图片。假设你已经在资源里定义了NormalImage(正常状态图)和LoadingImage(执行中图):
<Style TargetType="{x:Type local:CustomButton}"> <!-- 默认显示正常状态图片 --> <Setter Property="Content"> <Setter.Value> <Image Source="{StaticResource NormalImage}" /> </Setter.Value> </Setter> <!-- 当IsExecuting为True时切换到加载图 --> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Command.IsExecuting}" Value="True"> <Setter Property="Content"> <Setter.Value> <Image Source="{StaticResource LoadingImage}" /> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style>
为啥之前用CanExecuteChanged没成功?
CanExecuteChanged是用来通知命令是否可执行的,虽然你的AsyncCommand在IsExecuting变化时会触发这个事件,但它本质上是让UI更新按钮的可点击状态,不是直接关联IsExecuting的值。直接绑定Command.IsExecuting才是最直接准确的方式,毕竟这个属性就是专门用来标识命令是否在执行的。
4. 进阶:带复杂布局的按钮
如果按钮不止显示图片,还要加文字啥的,可以用ContentTemplate结合内部触发器来控制元素可见性:
<Style TargetType="{x:Type local:CustomButton}"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image x:Name="NormalImg" Source="{StaticResource NormalImage}" /> <Image x:Name="LoadingImg" Source="{StaticResource LoadingImage}" Visibility="Collapsed" /> <TextBlock Text="操作" Margin="5,0,0,0" /> </StackPanel> <DataTemplate.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:CustomButton}}, Path=Command.IsExecuting}" Value="True"> <Setter TargetName="NormalImg" Property="Visibility" Value="Collapsed" /> <Setter TargetName="LoadingImg" Property="Visibility" Value="Visible" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </Setter.Value> </Setter> </Style>
5. 最终使用
在XAML里直接用自定义按钮,绑定你的AsyncCommand就行:
<local:CustomButton Command="{Binding YourAsyncCommandInstance}" />
内容的提问来源于stack exchange,提问作者Taras
相关产品推荐
相关产品推荐

