Wpf 后台工作进程完成后绑定按钮未启用
我有一个后台工作进程,它开始为我们的系统配置一个新的客户端。以下是DoWork方法的外观:Wpf 后台工作进程完成后绑定按钮未启用,wpf,multithreading,backgroundworker,Wpf,Multithreading,Backgroundworker,我有一个后台工作进程,它开始为我们的系统配置一个新的客户端。以下是DoWork方法的外观: ProvisioningManager manager = new ProvisioningManager(false) { }; System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => { this.MaxSteps = manager.MaxProgress; })); manager.StatusUpd
ProvisioningManager manager = new ProvisioningManager(false)
{
};
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
this.MaxSteps = manager.MaxProgress;
}));
manager.StatusUpdated += new ProvisioningManager.StatusUpdatedHandler(manager_StatusUpdated);
manager.TaskCompleted += new ProvisioningManager.TaskCompleteHandler(manager_TaskCompleted);
manager.ProvisionClient();
while (!manager.Completed)
{
System.Threading.Thread.Sleep(100 * 60);
}
基本上,它创建了一个经理,负责与为客户提供服务的不同子系统进行对话
现在,我有了provisioning manager的状态更新事件和已完成事件。激发TaskCompleted事件时,我希望能够在显示对象上设置属性,以便启用向导中的“完成”按钮:
void manager_TaskCompleted(object sender, ProvisioningManager.Task taskType)
{
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
this.ProvisioningComplete = true;
}));
}
按钮的XAML如下所示:
<wizard:WizardPage Header="Provisioning Client..."
ShowBack="False"
AllowBack="False"
AllowFinish="{Binding Source={StaticResource ResourceKey=dataObject}, Path=ProvisioningComplete}"
Loaded="Provisioning_Loaded">
</wizard:WizardPage>
那也不行。什么给了我
更新
以下是为显示对象请求的静态资源实例化:
<Window.Resources>
<ObjectDataProvider x:Key="dataObject" ObjectType="{x:Type winDO:NewClientWizardDO}" />
</Window.Resources>
抱歉,如果我不理解某些内容,但是ProvisioningComplete属性是否标记为“volatile”?如果不是的话,这可能就是问题所在。所以我无法确切地找出我出现这个问题的原因。我尝试将焦点设置为窗口、按钮等。我尝试了多种方式让视图知道viewmodel已更新。基本上,我在网上找到的每一个建议都不起作用。它几乎像一只虫子 我团队的一个聪明人建议在窗口上假装鼠标点击。他的想法是,由于只需在屏幕上单击鼠标即可激活按钮,因此假装按下按钮也会产生同样的效果。我认为(并且认为)这种黑客行为是荒谬的。我确实试过了,只是想看看是否可以称之为“解决方案” 嗯,它起作用了。我们的另一个向导(不是AvalonWizard,而是一个自主开发的向导)也有同样的问题。我认为在后台线程更新绑定到UI的对象后,窗口重画的方式可能存在一些潜在问题 无论如何,我发现解决这个问题的方法是使用以下hack-tastic代码
//import user32.dll and setup the use of the mouse_event method
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
/// <summary>
/// Watches for properties to change on the data object, mainly the ProvisioningComplete method
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void DataObject_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ProvisioningComplete":
//if the provisioning is completed then we need to make the finish button selectable.
if (this.DataObject.ProvisioningComplete)
{
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
//give the window focus
this.Focus();
//update the layout
WizardPageProvisioningClient.UpdateLayout();
//fake mouse click 50 pixels into the window
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, (uint)(this.Left + 50), (uint)(this.Top + 50), 0, 0);
}));
}
break;
}
}
//导入user32.dll并设置鼠标事件方法的使用
[DllImport(“user32.dll”,CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
///
///监视数据对象上要更改的属性,主要是ProvisioningComplete方法
///
///
///
void DataObject_PropertyChanged(对象发送方,System.ComponentModel.PropertyChangedEventArgs e)
{
开关(如PropertyName)
{
案例“供应完成”:
//如果配置完成,那么我们需要选择finish按钮。
if(this.DataObject.ProvisioningComplete)
{
System.Windows.Application.Current.Dispatcher.Invoke((操作)(()=>
{
//给窗口焦点
这是Focus();
//更新布局
WizardPageProvisioningClient.UpdateLayout();
//假鼠标点击窗口50像素
鼠标事件(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP,(uint)(this.Left+50),(uint)(this.Top+50),0,0);
}));
}
打破
}
}
我已经在窗口不是活动窗口以及用户选择离开窗口时测试了这一点。当窗口处于非活动状态时,焦点方法似乎可以解决此问题。我们的QA团队还没有对UI进行完整的测试,所以我不能说是否有任何情况下它不起作用,但这似乎是我迄今为止提出的最佳解决方案
如果有人对导致按钮不更新的原因有更好的了解,我愿意接受任何其他建议。您可以发布静态资源“StaticResourceKey=dataObject”的声明吗?@Murven,请求的代码已添加到问题中。感谢您研究此问题。我假设NewClientWizardo实现INotifyPropertyChanged,并且property ProvisioningComplete触发PropertyChangedEvent。你能确认或张贴该课程的代码吗?很抱歉,我也应该要这个,如果不确定的话很难说。我可能已经找到了一个黑客补丁。我在视图中添加了一些代码,使用PropertyChanged事件作为显示对象。当它发现ProvisioningComplete已更改且为true时,我将获得向导页面并调用“UpdateLayout”。这似乎是可行的,但我还没有完全测试过。很抱歉,这篇文章有双重含义,但“UpdateLayout”不起作用。我想是的,但我可能已经从一个屏幕移到了另一个窗口,然后将焦点移回了该窗口,从而使按钮启用。仍然坚持这一点…我不知道你所说的标记一些不稳定的东西是什么意思。这是绑定标记还是属性上的属性?这里有一个示例和简短的解释似乎有意义,但遗憾的是,由于屏幕上没有用户活动,即使将volatile关键字添加到属性后面的字段中,按钮也不会将状态从禁用变为启用。我开始认为这可能是一个AvalonWizard错误。
public bool ProvisioningComplete
{
get { return this._ProvisioningComplete; }
set
{
this._ProvisioningComplete = value;
this.NotifyPropertyChanged("ProvisioningComplete");
}
}
protected void NotifyPropertyChanged(params string[] propertyNames)
{
if (this.PropertyChanged != null)
{
foreach (string propertyName in propertyNames)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//import user32.dll and setup the use of the mouse_event method
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
/// <summary>
/// Watches for properties to change on the data object, mainly the ProvisioningComplete method
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void DataObject_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ProvisioningComplete":
//if the provisioning is completed then we need to make the finish button selectable.
if (this.DataObject.ProvisioningComplete)
{
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
//give the window focus
this.Focus();
//update the layout
WizardPageProvisioningClient.UpdateLayout();
//fake mouse click 50 pixels into the window
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, (uint)(this.Left + 50), (uint)(this.Top + 50), 0, 0);
}));
}
break;
}
}