考虑以下代码:
struct X {
void MethodX() {
...
}
};
struct Y {
void MethodY() {
...
}
};
void test () {
X x;
Y y;
Dispatcher d;
d.Register("x", x, &X::MethodX);
d.Register("y", y, &Y::MethodY);
d.Call("x");
d.Call("y");
}
Run Code Online (Sandbox Code Playgroud)
问题是如何实现Dispatcher.我不介意X和Y可以继承某些东西,但是Dispatcher应该允许更多的客户端(不仅仅是X和Y).如果可能的话我想避免使用void*指针:)
曾几何时,我记得这些东西.随着时间的推移,我的理解已经淡化,我的意思是刷新它.
我记得,任何所谓的单线程应用程序都有两个线程:
a)具有指向main或DllMain入口点的指针的主线程; 和
b)对于具有一些UI的应用程序,运行WndProc的UI线程(也称为辅助线程),即执行WndProc的线程,该线程接收Windows发布给它的消息.简而言之,执行Windows消息循环的线程.
对于UI应用程序,主线程处于阻塞状态,等待来自Windows的消息.当它收到它们时,它会将它们排队并将它们分派到消息循环(WndProc)并启动UI线程.
根据我的理解,处于阻塞状态的主线程是这样的:
while(getmessage(/* args &msg, etc. */))
{
translatemessage(&msg, 0, 0);
dispatchmessage(&msg, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
Application.Run( new System.Windows.Forms() );
Run Code Online (Sandbox Code Playgroud)
这就是他们所谓的调度员吗?
我的问题是:
a)我的上述理解是否正确?
b)调度员到底是什么名字?
c)指向一个资源,我可以从Windows/Win32的角度更好地理解线程,然后将它与C#等高级语言联系起来.佩佐尔德在他的史诗作品中不遗余力地讨论这个问题.
虽然我相信我有点对,但确认会有所缓解.
因为两天我试图解决以下问题:我有一个WPF控件,其中WrapPanel绑定到ObservableCollection.操作会更改ObservableCollection的内容.内容将加载到BackgroundWorker中.在导致内容更改的操作之后,在foreach循环中需要新内容.问题是内容的加载速度很慢,所以需要一点准备.
我的第一次尝试是等待后台工作,直到IsBusy属性设置为false.但IsBusy的财产在等待期间从未改变过!第二次尝试是尝试直接从BackgroundWorker操作ObservableCollection.当然没有成功,因为ObservableCollection在另一个线程中而不是BackgroundWorker.
我真的非常了解如何在跨线程范围内操作内容.但它们都没有奏效.使用Dispatcher尝试解决方案,"ThreadSafeObservableCollection",.....
有谁能告诉我如何解决这个问题?是否有一种简单的方法来编辑另一个线程中的UI线程的内容?或者我如何正确等待BackgroundWorker完成?
编辑: 但我怎么能等待BackgroundWorker完成???
我发现很少有关于如何正确使用Dispatcher类的信息.
目前我使用它类似于这个问题,但有一个固有的竞争条件,我没有看到任何地方提到.
假设您使用以下代码启动调度程序线程:
Thread thread = new Thread(Dispatcher.Run);
thread.Start();
Run Code Online (Sandbox Code Playgroud)
并尝试以后使用它:
Dispatcher.FromThread(thread).Invoke(MyMethodDelegate);
Run Code Online (Sandbox Code Playgroud)
这通常会抛出NullReferenceException,因为Dispatcher.FromThread调用可能会返回null,因为无法保证已调用Dispatcher.Run.
我为实现这一点而做的是使用一个信号来确保调度程序在继续在主线程上使用之前运行.
我想使用cherrypy,但我不想使用普通的调度程序,我想要一个能够捕获所有请求然后执行我的代码的函数.我认为我必须实现自己的调度程序,但我找不到任何有效的例子.你可以通过发布一些代码或链接来帮助我吗?
谢谢
我试图调用一个方法,该方法在调用BeginInvoke的UI线程上的后台线程上启动,并传递一个委托,如下所示:
Dispatcher.BeginInvoke(Function() UpdateApplicationDataUI())
Run Code Online (Sandbox Code Playgroud)
调用此方法:
Private Sub UpdateApplicationDataUI()
...
End Sub
Run Code Online (Sandbox Code Playgroud)
但是,我在调用BeginInvoke时遇到错误(委托的UpdateApplicationDataUI部分声明"Expression不生成值").我确定我错过了一些简单的东西...任何想法?
做了更多研究并回答了我自己的问题:
Me.Dispatcher.BeginInvoke(Function() New Action(AddressOf UpdateApplicationDataUI))
Run Code Online (Sandbox Code Playgroud) 我有一个ListBox风格使用RadioButtons,并更改它SelectedItem也会更改UserControl显示在它ContentControl下面.该应用程序如下所示:

<ListBox ItemsSource="{Binding AvailableViewModels}"
SelectedItem="{Binding SelectedViewModel}"
Style="{StaticResource RadioButtonListBoxStyle}" />
<ContentControl Content="{Binding SelectedViewModel}" />
Run Code Online (Sandbox Code Playgroud)
我的问题是UserControls每个都包含一个自定义的网格控件(Telerik RadGridView),由于它包含的数据量,它在加载时有明显的延迟.
我在Grid加载后ItemsSource在Loaded事件中设置绑定以防止UI在Grid加载时锁定,但无论我如何尝试运行它,RadioButtons仍然反映加载时的延迟,这给出了冻结的错觉UI

我尝试使用尽可能低的DispatcherPriority来设置绑定,但它似乎没有什么区别.
XAML:
<telerik:RadGridView x:Name="MyGrid" Loaded="MyGrid_Loaded" Unloaded="MyGrid_Unloaded">
<!--....-->
</telerik:RadGridView>
Run Code Online (Sandbox Code Playgroud)
C#:
private void MyGrid_Loaded(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
new Action(delegate()
{
BindingOperations.SetBinding(
MyGrid,
RadGridView.ItemsSourceProperty,
new Binding("ViewModelProperty")
);
}));
}
private void MyGrid_Unloaded(object sender, RoutedEventArgs e)
{
MyGrid.ItemsSource = null;
}
Run Code Online (Sandbox Code Playgroud)
应该注意的是,每次UserControl加载时,它都会很好地加载,RadioButton选择立即改变,并在几秒钟后加载网格.它只能切换到一个UserControl …
我正在编写一个程序来监视从串口发送的命令(来自arduino)并将键击发送到各种其他程序.
我已经在我的活动中安排了一个调度员,但它只会运行一次......我已经完成了代码,它一直运行到第一次但不是第二次.
private void portReadEvent(object sender, SerialDataReceivedEventArgs args)
{ //break here
Action dump = delegate()
{
dumpInfoText(serialPort.ReadExisting());
}; //create my deligate
txt_portInfo.Dispatcher.Invoke(dump); //run dispatcher
}
private void dumpInfoText(string text)
{
string completeCommand = "";
foreach (char C in text)
{
if (serDump.Length <=8 && (C != (char)0x0A || C != (char)0x0D)) //check
{
serDump = serDump + C; //add char
}
if (serDump.Length == 8) //check to see if my info has a complete command (serDump is global)
{
completeCommand …Run Code Online (Sandbox Code Playgroud) 我试过下面的片段:
public Task RunUiTask(Action action)
{
var task = Task.Factory.StartNew(() =>
{
Dispatcher.Invoke(DispatcherPriority.Background, action);
});
return task;
}
private void OnCreateTask(object sender, RoutedEventArgs e)
{
var task = RunUiTask(() =>
{
for(int i=0;i<10;i++)
{
ResultTextBlock.Text += i.ToString();
}
});
task.Wait(); //(a) Program stopped here
ResultTextBlock.Text += "Finished"; //(b) Never called;
}
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么,当调用OnCreateTask(按钮单击事件处理程序)时,程序在(a)处停止,而(b)从不被调用.
注意:我知道我可以使用Dispatcher.BeginInvoke来使程序响应,但这不是我关注的问题.
任何人都可以告诉为什么程序在(a)处停止,为什么(b)从未被调用?谢谢.
最近,我发现了一种方法,该方法执行调度程序队列中的所有待处理消息,直到指定优先级为止。我之前已经有这样的代码,但是它们使用完全不同的方法。这两个都是:
PushFrame方式:
/// <summary>
/// Enters the message loop to process all pending messages down to the specified
/// priority. This method returns after all messages have been processed.
/// </summary>
/// <param name="priority">Minimum priority of the messages to process.</param>
public static void DoEvents(
DispatcherPriority priority = DispatcherPriority.Background)
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
priority,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object f)
{
((DispatcherFrame) f).Continue = false;
return null;
}
Run Code Online (Sandbox Code Playgroud)
来源:MSDN库
阻止调用方式:
private static Action …Run Code Online (Sandbox Code Playgroud)