单击按钮时可以更改图像,但是当尝试在更改后运行方法时,更改永远不会发生。
我有两种方法可以在按钮的单击事件上更改图像
第一:
<Window.Resources>
<Image x:Key="ImON" Source="InterruptorON.png" Height="315" Width="435" />
<Image x:Key="ImOFF" Source="InterruptorOFF.png" Height="315" Width="435" />
</Window.Resources>
<Grid>
<Button Name="btnEXE" Height="315" Width="435" Click="Button_Click">
<DynamicResource ResourceKey="ImOFF"/>
</Button>
</Grid>
btnEXE.Content = FindResource("ImON");
第二:
<Window.Resources>
<ControlTemplate x:Key="ImOFF" TargetType="Button">
<Image Source="InterruptorOFF.png" Height="315" Width="435" />
</ControlTemplate>
<ControlTemplate x:Key="ImON" TargetType="Button">
<Image Source="InterruptorON.png" Height="315" Width="435" />
</ControlTemplate>
</Window.Resources>
<Grid>
<Button Name="btnEXE" Height="315" Width="435" Click="Button_Click" Template="{StaticResource ImOFF}"/>
</Grid>
btnEXE.Template = (ControlTemplate)FindResource("ImON")
我需要使用if()
来验证按钮的“ ON”或“ OFF”状态以更改图像并运行其他代码
if (btnEXE.Content == FindResource("ImOFF"))
{
btnEXE.Content = FindResource("ImON");
ThingsToDo();
}
else
{
btnEXE.Content = FindResource("ImOFF");
}
ThingsToDo()
运行完美,但是图像的更改一直发生到方法结束为止。
我需要先更改图像,然后再更改其余代码。 有想法吗?
答案 0 :(得分:1)
如果ThingsToDo
是长期运行的操作,则应通过Task
和await
运行它:
await Task.Run(() => ThingsToDo());
我还建议使用BitmapImage
资源,而不是使用重量较大的Image
元素:
<Window.Resources>
<BitmapImage x:Key="ImON" UriSource="InterruptorON.png"/>
<BitmapImage x:Key="ImOFF" UriSource="InterruptorOFF.png"/>
</Window.Resources>
<Grid>
<Button Height="315" Width="435" Click="Button_Click">
<Image Source="{StaticResource ImOFF}" Height="315" Width="435"/>
</Button>
</Grid>
并在异步事件处理程序中使用它们。此外,请确保只要该操作在运行,就禁用按钮。
private async void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var image = (Image)button.Content;
var imOff = (ImageSource)FindResource("ImOFF");
if (image.Source == imOff)
{
image.Source = (ImageSource)FindResource("ImON");
button.IsEnabled = false;
await Task.Run(() => ThingsToDo());
button.IsEnabled = true;
}
else
{
image.Source = imOff;
}
}
答案 1 :(得分:0)
即使您不打算走完整的MVVM路线,仍然可以使用WPF命令来处理此类UI更新。
假设ThingsToDo()是一个长期运行的任务,则应通过ICommand实现使用async / await构造。
public class RelayCommandAsync : ObservableObject, ICommand
{
private readonly Func<Task> _execute;
private readonly Func<bool> _canExecute;
public RelayCommandAsync(Func<Task> execute) : this(execute, () => true)
{
}
public RelayCommandAsync(Func<Task> execute, Func<bool> canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
private bool _isExecuting;
public bool IsExecuting
{
get => _isExecuting;
set
{
if (Set(nameof(IsExecuting), ref _isExecuting, value))
RaiseCanExecuteChanged();
}
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => !IsExecuting && _canExecute();
public async void Execute(object parameter)
{
if (!CanExecute(parameter))
return;
IsExecuting = true;
try
{
await _execute().ConfigureAwait(true);
}
finally
{
IsExecuting = false;
}
}
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
ObservableObject来自MVVMLight框架,但是您可以将其替换为任何INotifyPropertyChanged实现。
然后可以在窗口后面的代码中分配它
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
btnExe.Command = new RelayCommandAsync(ThingsToDo);
}
private async Task ThingsToDo()
{
// simulate a long running operation
await Task.Delay(TimeSpan.FromSeconds(3));
}
}
然后,您可以使用Windows的xaml文件中的样式定义按钮的外观,其中包括绑定到用于更新图像的命令的IsExecuting属性的触发器。
<Button x:Name="btnExe">
<Button.Resources>
<Image x:Key="ImgOff" Source="InterruptorOFF.png" />
<Image x:Key="ImgOn" Source="InterruptorON.png" />
<Button.Resources>
<Button.Style>
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
<Setter Property="Content" Value="{StaticResource ImgOff}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Command.IsExecuting}" Value="True">
<Setter Property="Content" Value="{StaticResource ImgOn}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
使用此构造可带来额外的好处,即在执行命令时禁用按钮(由于Command.CanExecute),从而防止用户多次触发命令。