这两个片段之间究竟有什么区别:
A:
MyDataGrid.IsKeyboardFocusWithinChanged += (sender, e) => {
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
{
// do something
}));
}
};
B:
MyDataGrid.IsKeyboardFocusWithinChanged += (sender, e) => {
if ((bool)e.NewValue == true)
{
Dispatcher.Invoke(DispatcherPriority.Loaded, new Action(() =>
{
// do something
}));
}
};
我认为Invoke
和BeginInvoke
之间的唯一区别是第一个等待任务完成而后者立即返回。由于Dispatcher
调用是EventHandler
中唯一发生的事情,因此我认为在这种情况下使用Invoke
与使用BeginInvoke
具有完全相同的效果。但是我有一个工作的例子,显然并非如此。看看你自己:
MainWindow.xaml
<Window x:Class="DataGridFocusTest.MainWindow"
x:Name="MyWindow"
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:local="clr-namespace:DataGridFocusTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<TextBox DockPanel.Dock="Top"></TextBox>
<DataGrid x:Name="MyDataGrid" DockPanel.Dock="Top" SelectionUnit="FullRow"
ItemsSource="{Binding SomeNumbers, ElementName=MyWindow}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Data" Binding="{Binding Data}"
IsReadOnly="True" />
<DataGridTemplateColumn Header="CheckBox">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace DataGridFocusTest
{
public class MyDataClass
{
public string Data { get; set; }
}
public partial class MainWindow : Window
{
public IList<MyDataClass> SomeNumbers
{
get
{
Random rnd = new Random();
List<MyDataClass> list = new List<MyDataClass>();
for (int i = 0; i < 100; i++)
{
list.Add(new MyDataClass() { Data = rnd.Next(1000).ToString() });
}
return list;
}
}
public MainWindow()
{
InitializeComponent();
MyDataGrid.IsKeyboardFocusWithinChanged += (sender, e) =>
{
if ((bool)e.NewValue == true)
{
// whenever MyDataGrid gets KeyboardFocus set focus to
// the selected item
// this has to be delayed to prevent some weird mouse interaction
Dispatcher.Invoke(DispatcherPriority.Loaded, new Action(() =>
{
if (MyDataGrid.IsKeyboardFocusWithin &&
MyDataGrid.SelectedItem != null)
{
MyDataGrid.UpdateLayout();
var cellcontent = MyDataGrid.Columns[1].GetCellContent(MyDataGrid.SelectedItem);
var cell = cellcontent?.Parent as DataGridCell;
if (cell != null)
{
cell.Focus();
}
}
}));
}
};
}
}
}
我们这里有一个DataGrid
,其中的行包含CheckBox
。它实现了两种特定的行为:
DataGrid
获得键盘焦点时,它会聚焦所选行(由于某种原因,这不是默认行为)。CheckBox
没有聚焦,您也可以通过单击更改DataGrid
的状态。这已经有效了。假设在帖子的顶部,我认为使用Invoke
或BeginInvoke
并不重要。但是,如果您将代码更改为BeginInvoke
,则由于某种原因,2cnd行为(一键式复选框选择)不再起作用。
我不寻找解决方案(解决方案只是使用Invoke
),而是想知道为什么Invoke
和BeginInvoke
在这种情况下表现得如此不同。