我在处理函数期间在WPF应用程序中禁用控件时遇到问题。它是通过串口发送数据的简单应用程序。当端口是"听" (SerialPort.ReadChar();)我希望所有控件都变灰/禁用它们。
这样:
private void startTransmissionButton_Click(object sender, RoutedEventArgs e)
{
ComboBox.IsEnabled = false;
Button1.IsEnabled = false;
Button2.IsEnabled = false;
Button3.IsEnabled = false;
SerialPort com = new SerialPort("COM1");
com.Open();
c = (char)com.ReadChar();
com.Close();
ComboBox.IsEnabled = true;
Button1.IsEnabled = true;
Button2.IsEnabled = true;
Button3.IsEnabled = true;
}
禁用似乎只在函数内部起作用,因此窗口中实际上没有任何内容。当我在函数结束时删除启用时,所有控件都变为灰色,但不是*.IsEnabled = false
指令时,而是函数结束时。有什么我做错了或一切都好,这需要以不同的方式完成吗?
答案 0 :(得分:1)
欢迎使用StackOverflow!
由于您的代码是同步的,因此它是阻塞的,因此您获得的行为。还需要考虑使用Dispatcher
,但幸运的是,您还没有遇到过这样的问题。
<强>建议:强>
示例:禁用用户界面的5秒钟工作(非常简单!)
我的代码中的兴趣点:
StackPanel
内禁用的控件放入IsEnabled
属性并将其IsAvailable
属性绑定到我有效简化此过程<强> XAML:强>
<Window x:Class="WpfApplication1.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainView"
Width="525"
Height="350"
d:DataContext="{d:DesignInstance wpfApplication1:MainViewModel,
d:IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<Grid>
<StackPanel>
<Button Command="{Binding DoSomeWork}" Content="Do some long work" />
<StackPanel IsEnabled="{Binding IsAvailable}">
<CheckBox Content="Test control 1" />
<RadioButton Content="Test control 2" />
</StackPanel>
<TextBlock Text="Overall progress:" />
<ProgressBar Height="10" Value="{Binding CurrentProgress}" />
</StackPanel>
</Grid>
</Window>
<强>代码隐藏:强>
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
// put classes shown below here
}
您的型号:
internal class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
// set-up environment
DoSomeWork = new DelegateCommand(DoSomeWorkExecute, DoSomeWorkCanExecute);
IsAvailable = true;
}
public int CurrentProgress
{
get { return _currentProgress; }
set
{
_currentProgress = value;
OnPropertyChanged();
}
}
#region IsAvailable
private bool _isAvailable;
private int _currentProgress;
public bool IsAvailable
{
get { return _isAvailable; }
set
{
_isAvailable = value;
OnPropertyChanged();
}
}
#endregion
#region DoSomeWork
public DelegateCommand DoSomeWork { get; private set; }
private bool DoSomeWorkCanExecute(object arg)
{
return true;
}
private async void DoSomeWorkExecute(object o)
{
await Task.Run(() =>
{
IsAvailable = false;
var steps = 20;
var time = 5000;
var length = time/steps;
for (var i = 0; i < steps; i++)
{
Thread.Sleep(length);
var currentProgress = (int) (((((double) i + 1)*length)/time)*100);
CurrentProgress = currentProgress;
}
IsAvailable = true;
});
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
DoSomeWork
的一个简单的命令库:
internal class DelegateCommand : ICommand
{
private readonly Func<object, bool> _canExecute;
private readonly Action<object> _execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public DelegateCommand(Action<object> execute)
: this(execute, s => true)
{
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged;
}
<强> TODO 强>
熟悉:
第一次使用这些概念时会遇到一些痛苦,但随着时间的推移,你会发现这些是特别的方法。与WPF。
如果您对我的回答感到满意,请将其标记为答案,否则如果您需要澄清,请在下方添加评论,我或其他人会尝试进一步提供帮助。
答案 1 :(得分:0)
请阅读Aybe提供的完整答案。遵循最佳实践总是好的。但是当谈到小型快速测试项目时,我相信有时它可能是一种过度杀伤。
如果您需要快速解决此问题,那么您可以尝试使用以下方法:
private async void startTransmissionButton_Click(object sender, RoutedEventArgs e)
{
ComboBox.IsEnabled = false;
Button1.IsEnabled = false;
Button2.IsEnabled = false;
Button3.IsEnabled = false;
await
Task.Factory.StartNew(
() =>
{
SerialPort com = new SerialPort("COM1");
com.Open();
c = (char)com.ReadChar();
com.Close();
}
);
ComboBox.IsEnabled = true;
Button1.IsEnabled = true;
Button2.IsEnabled = true;
Button3.IsEnabled = true;
}
请注意,为c
变量赋值会在另一个线程中发生。
我希望我的回答很有帮助。