我有以下示例代码,每次按下按钮时都会缩放:
XAML:
<Window x:Class="WpfApplication12.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas x:Name="myCanvas">
<Canvas.LayoutTransform>
<ScaleTransform x:Name="myScaleTransform" />
</Canvas.LayoutTransform>
<Button Content="Button"
Name="myButton"
Canvas.Left="50"
Canvas.Top="50"
Click="myButton_Click" />
</Canvas>
</Window>
* CS
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("scale {0}, location: {1}",
myScaleTransform.ScaleX,
myCanvas.PointToScreen(GetMyByttonLocation()));
myScaleTransform.ScaleX =
myScaleTransform.ScaleY =
myScaleTransform.ScaleX + 1;
Console.WriteLine("scale {0}, location: {1}",
myScaleTransform.ScaleX,
myCanvas.PointToScreen(GetMyByttonLocation()));
}
private Point GetMyByttonLocation()
{
return new Point(
Canvas.GetLeft(myButton),
Canvas.GetTop(myButton));
}
}
输出是:
scale 1, location: 296;315
scale 2, location: 296;315
scale 2, location: 346;365
scale 3, location: 346;365
scale 3, location: 396;415
scale 4, location: 396;415
正如您所看到的那样,有一个问题,我认为使用Application.DoEvents();
解决但是......它在.NET 4中不存在先验。
怎么办?
答案 0 :(得分:121)
尝试这样的事情
public static void DoEvents()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
new Action(delegate { }));
}
答案 1 :(得分:50)
好吧,我刚刚开始研究一个在Dispatcher线程上运行的方法的情况,它需要在不阻塞UI线程的情况下阻塞。事实证明,msdn解释了如何基于Dispatcher本身实现DoEvents():
public void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
答案 2 :(得分:23)
旧的Application.DoEvents()方法已在WPF中弃用,支持使用Dispatcher或Background Worker Thread进行处理,如您所述。有关如何使用这两个对象的文章,请参阅链接。
如果您绝对必须使用Application.DoEvents(),那么您只需将system.windows.forms.dll导入您的应用程序并调用该方法即可。但是,我们不建议这样做,因为您正在失去WPF提供的所有优势。
答案 3 :(得分:5)
myCanvas.UpdateLayout();
似乎也有效。
答案 4 :(得分:5)
如果您只需更新窗口图形,请更好地使用
public static void DoEvents()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Render,
new Action(delegate { }));
}
答案 5 :(得分:3)
两种提议方法的一个问题是它们需要空闲的CPU使用率(根据我的经验,高达12%)。在某些情况下,这是次优的,例如,当使用此技术实现模态UI行为时。
以下变化引入了使用定时器的帧之间的最小延迟(请注意,此处使用Rx写入,但可以使用任何常规定时器实现):
var minFrameDelay = Observable.Interval(TimeSpan.FromMilliseconds(50)).Take(1).Replay();
minFrameDelay.Connect();
// synchronously add a low-priority no-op to the Dispatcher's queue
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => minFrameDelay.Wait()));
答案 6 :(得分:1)
自async
和await
引入后,现在可以使用Task.Delay
在(以前)*同步代码块中途放弃UI线程,例如
private async void myButton_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("scale {0}, location: {1}",
myScaleTransform.ScaleX,
myCanvas.PointToScreen(GetMyByttonLocation()));
myScaleTransform.ScaleX =
myScaleTransform.ScaleY =
myScaleTransform.ScaleX + 1;
await Task.Delay(1); // In my experiments, 0 doesn't work. Also, I have noticed
// that I need to add as much as 100ms to allow the visual tree
// to complete its arrange cycle and for properties to get their
// final values (as opposed to NaN for widths etc.)
Console.WriteLine("scale {0}, location: {1}",
myScaleTransform.ScaleX,
myCanvas.PointToScreen(GetMyByttonLocation()));
}
我会说实话,我没有尝试过上面的确切代码,但是当我将许多项目放入ItemsControl
时,我会在紧凑的循环中使用它,这有一个昂贵的项目模板,有时候添加一个小延迟,以便为UI上的其他内容提供更多时间。
例如:
var levelOptions = new ObservableCollection<GameLevelChoiceItem>();
this.ViewModel[LevelOptionsViewModelKey] = levelOptions;
var syllabus = await this.LevelRepository.GetSyllabusAsync();
foreach (var level in syllabus.Levels)
{
foreach (var subLevel in level.SubLevels)
{
var abilities = new List<GamePlayingAbility>(100);
foreach (var g in subLevel.Games)
{
var gwa = await this.MetricsRepository.GetGamePlayingAbilityAsync(g.Value);
abilities.Add(gwa);
}
double PlayingScore = AssessmentMetricsProcessor.ComputePlayingLevelAbility(abilities);
levelOptions.Add(new GameLevelChoiceItem()
{
LevelAbilityMetric = PlayingScore,
AbilityCaption = PlayingScore.ToString(),
LevelCaption = subLevel.Name,
LevelDescriptor = level.Ordinal + "." + subLevel.Ordinal,
LevelLevels = subLevel.Games.Select(g => g.Value),
});
await Task.Delay(100);
}
}
在Windows应用商店中,当集合上有一个很好的主题转换时,效果非常理想。
路
答案 7 :(得分:0)
在WPF中制作您的DoEvent():
Thread t = new Thread(() => {
// do some thing in thread
for (var i = 0; i < 500; i++)
{
Thread.Sleep(10); // in thread
// call owner thread
this.Dispatcher.Invoke(() => {
MediaItem uc = new MediaItem();
wpnList.Children.Add(uc);
});
}
});
t.TrySetApartmentState(ApartmentState.STA); //for using Clipboard in Threading
t.Start();
为我工作好!
答案 8 :(得分:-2)
回答原始问题:DoEvents在哪里?
我认为DoEvents是VBA。而且VBA似乎没有睡眠功能。但是VBA可以达到与“睡眠”或“延迟”完全相同的效果。在我看来,DoEvents等同于Sleep(0)。
在VB和C#中,您正在使用.NET。最初的问题是C#问题。在C#中,您将使用Thread.Sleep(0),其中0是0毫秒。
您需要
targert=start2
位于文件顶部以便使用
using System.Threading.Task;
在您的代码中。