我在里面创建了一个带有TextBlock的Window。我绑定了Text属性,一切正常。 的 BUT 当我在任务中更改有界属性时,没有任何作用!!
你知道为什么吗?
Public Async Sub StartProgress()
Try
LoadingText = "text 1" 'Works perfect
Dim fResult As Boolean = Await LoadModules()
If Not fResult Then
MessageBox.Show(Me.Error)
End If
m_oView.Close()
Catch ex As Exception
Msg_Err(ex)
End Try
End Sub
Public Async Function LoadModules() As Task(Of Boolean)
Try
Await Task.Delay(3000)
LoadingText = "text 2" 'Nothing Happens
Await Task.Delay(5000)
LoadingText = "complete" 'Nothing Happens
Await Task.Delay(3000)
Return True
Catch ex As Exception
Me.Error = ex.Message
Return False
End Try
End Function
永远不会显示文本2和3。如果我动态更改textblcok的文本(例如:m_oView.txtLoadingText.Text)它工作正常(但它不是解决方案)
修改 这是ViewModel Base,每个ViewModel实现该类。
Public Class VM_Base
Implements IDisposable
Implements INotifyPropertyChanged
Private m_oDS As MxDataSet
Public Property [Error] As String
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Protected Sub New()
m_oDS = New MxDataSet
End Sub
Protected Overrides Sub Finalize()
Try
Me.Dispose(False)
Debug.Fail("Dispose not called on ViewModel class.")
Finally
MyBase.Finalize()
End Try
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
End Sub
Protected Overridable Sub OnPropertyChanged(propertyName As String)
Me.EnsureProperty(propertyName)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
<Conditional("DEBUG")> _
Private Sub EnsureProperty(propertyName As String)
If TypeDescriptor.GetProperties(Me)(propertyName) Is Nothing Then
Throw New ArgumentException("Property does not exist.", "propertyName")
End If
End Sub
End Class
如何调用StartProgress:
<i:Interaction.Triggers>
<i:EventTrigger EventName="ContentRendered">
<i:InvokeCommandAction Command="{Binding DataContext.WindowsActivatedCommand,ElementName=fLoading}" />
</i:EventTrigger>
</i:Interaction.Triggers>
修改 将TextBlock绑定到Property
Public Property LoadingText As String
Get
Return m_sLoadingText
End Get
Set(value As String)
m_sLoadingText = value
OnPropertyChanged("LoadingText")
End Set
End Property
<TextBlock x:Name="txtLoading" Width="450"
Grid.Row="1" VerticalAlignment="Center"
HorizontalAlignment="Left"
TextWrapping="Wrap" Text="{Binding LoadingText}">
</TextBlock>
答案 0 :(得分:1)
以下是您需要做的详细解答,以确保源自非UI线程的调用正确调用UI方法:
答案 1 :(得分:1)
您需要在视图模型类型上实现INotifyPropertyChanged
,并让LoadingText
setter引发该事件。
答案 2 :(得分:1)
@ Manolis Xountasis,
我不知道VB.net,但我在C#中测试代码,没关系。以下是我的代码:
public partial class MainWindow : Window
{
private TestViewModel _tvm = new TestViewModel();
public MainWindow()
{
InitializeComponent();
this.wndTest.DataContext = _tvm;
_tvm.TestData = "First Data";
this.btnAsync.Click += BtnAsyncOnClick;
}
private void BtnAsyncOnClick(object sender, RoutedEventArgs routedEventArgs)
{
var task = Task.Factory.StartNew(() => this.Dispatcher.Invoke(new Action(() => _tvm.TestData = "changed data")));
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfApplication3.MainWindow"
x:Name="wndTest"
Title="MainWindow"
Height="350"
Width="525">
<!--<Window.Resources>
<local:TestViewModel x:Key="TestViewModelDataSource" d:IsDataSource="True"/>
</Window.Resources>
<Window.DataContext>
<Binding Mode="OneWay" Source="{StaticResource TestViewModelDataSource}"/>
</Window.DataContext>-->
<Grid>
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding TestData}" />
<Button x:Name="btnAsync" Content="Change Async" HorizontalAlignment="Right" VerticalAlignment="Top"/>
</Grid>
希望此代码对您有用。
答案 3 :(得分:1)
根据这个page(强调我的):
现在这可能会吓跑你的C#异步语言功能, 因为它让它们看起来很慢,但这不是一个公平的考验。该 之所以需要这么长时间,是因为我们给了这个程序很多 还有更多工作要做。当简单的同步版本在UI上运行时 线程,WPF对我们添加的每个项目都做了很少的即时工作 LogUris系列。 数据绑定将检测到变化 - 我们 将ListBox绑定到该集合,因此它将寻找更改 通知事件 - 但WPF不会完全处理这些更改,直到 我们的代码已经完成了UI线程。数据绑定推迟了它的工作 直到调度程序线程没有更高优先级的工作要做。
如果您通过调度程序更新属性,这可能就是它的原因。您是否尝试通过GetBindingExpression(Property).UpdateTarget()
2强制更新目标?
答案 4 :(得分:0)
现在你可以这样做
在表单/窗口
的构造函数中btnAddNewCard.Click += async (s, e) => await BtnAddNewCard_ClickAsync(s, e);
private async Task BtnAddNewCard_ClickAsync(object sender, RoutedEventArgs e)
{
// Any code like
await ShowOKMessageAsync(msg);
}