Wpf 当代码从主UI线程移动到类时,UI组件在当前上下文中不存在
我目前有一个在MainWindow.xaml.cs中实现的工作代码,我正试图将其移动到一个类,该类给我一个错误,即我的UI标签在当前上下文中不存在 以下是在主窗口中工作的代码:Wpf 当代码从主UI线程移动到类时,UI组件在当前上下文中不存在,wpf,task-parallel-library,Wpf,Task Parallel Library,我目前有一个在MainWindow.xaml.cs中实现的工作代码,我正试图将其移动到一个类,该类给我一个错误,即我的UI标签在当前上下文中不存在 以下是在主窗口中工作的代码: public partial class MainWindow : Window { ...... private RX consumer = new RX(); private void Window_Loaded(object sender, RoutedEventArgs e) {
public partial class MainWindow : Window
{
......
private RX consumer = new RX();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
Task backgroundDBTask = Task.Factory.StartNew(() => { Consumer(consumer);}, TaskCreationOptions.LongRunning);
}
}
public void Consumer(Consumer consumer)
{
while (true)
{
Thread.Sleep(1000);
.......
Dispatcher.BeginInvoke(new Action(() =>
{
mylbl.Content = value.ToString();
}), DispatcherPriority.Background);
}
}
然后我尝试将代码移动到一个单独的类:
public partial class MainWindow : Window
{
....
private RX consumer = new RX();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
Task backgroundDBTask = Task.Factory.StartNew(() => { consumer.ProcessMessages(); }, TaskCreationOptions.LongRunning);
}
}
}
public class RX
{
public void ProcessMessages()
{
while (true)
{
Thread.Sleep(1000);
....
var m_dispatcher = Application.Current.MainWindow;
m_dispatcher.Dispatcher.BeginInvoke(new Action(() =>
{
mylbl.Content = value.ToString();
}), DispatcherPriority.Background);
}
}
}
我得到的错误是:
mylbl.Content=value.ToString()
来自RX类。我按照建议使用var m_dispatcher=Application.Current.MainWindow来访问MainWindow线程,但仍然出现错误。您不能从MyWindow之外的其他类访问MyBL,因为它是在那里定义的。 您可以实现MVVM,将内容属性绑定到视图模型中的字符串,并更新内容 或者分离业务逻辑以分离类,并将其公开给MyWindow.Xaml.cs 您可以有一个在RX中返回“value”的公共方法。您可以通过访问此方法更新MyWindow.xaml.cs中的内容 或者将Label实例传递给ProcessMessage方法并更新内容。当然,在类中添加一个参考System.Windows.Controls 然而,这不是一个好的设计。我建议你通过MVVM
public void ProcessMessages(Label mylbl)
{
while (true)
{
Thread.Sleep(1000);
....
var m_dispatcher = Application.Current.MainWindow;
m_dispatcher.Dispatcher.BeginInvoke(new Action(() =>
{
mylbl.Content = value.ToString();
}), DispatcherPriority.Background);
}
}
打电话的人看起来像这样
public partial class MainWindow : Window
{
....
private RX consumer = new RX();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
Task backgroundDBTask = Task.Factory.StartNew(() => { consumer.ProcessMessages(mylbl); }, TaskCreationOptions.LongRunning);
}
}
}
正如克莱门斯所建议的,我正在以MVVM的方式更新解决方案。
XAML部分:
<Window x:Class="MvvmExample.MainWindow"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MvvmExample"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid >
<Label Content="{Binding LableContent}" Height="100" Width="500" Foreground="Red"/>
</Grid>
</Window>
我对命令使用了ICommand实现。
我还使用INotifyPropertyChanged进行绑定
我假设您已经了解了以下主题,如果没有的话,stack overflow中有很多关于这些主题的帮助
mylbl
是MainWindow类的成员,可以从同一个类中的Consumer方法访问该类,但显然不能从另一个类访问该类。我是否可以这样做?我见过很多帖子使用这个:var m_dispatcher=Application.Current.MainWindow来访问MainWindow线程,但它仍然不起作用。或者我只是把代码放在主窗口上?你能告诉我怎么做最后的建议吗。我认为这将是实现这一目标的最简单方法。谢谢。我仍然有一个来自mylbl.Content=value.ToString()的错误;另外,我从不从ProcessMessages返回,因为它是一个while(true)循环。它是一个listener.ProcessMessages是一个名为from的后台任务;公共部分类主窗口:窗口{….private RX consumer=new RX();private void Window_Loaded(对象发送方,RoutedEventArgs e){try{Task backgroundDBTask=Task.Factory.StartNew(()=>{consumer.ProcessMessages();},TaskCreationOptions.LongRunning);}}请将mylbl实例传递给ProcessMessages,如编辑的答案所示。并将Label控件作为ProcessMessage方法中的参数
public class ViewModel : INotifyPropertyChanged
{
#region Constants and Enums
#endregion
#region Private and Protected Member Variables
private string _lableContent;
#endregion
#region Private and Protected Methods
private void OnLoaded(object obj)
{
Task.Factory.StartNew(() => { ProcessMessages(); }, TaskCreationOptions.LongRunning);
}
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Constructors
public ViewModel()
{
LoadedCommand = new RelayCommand(OnLoaded);
}
#endregion
#region Public Properties
public event PropertyChangedEventHandler PropertyChanged;
public string LableContent
{
get
{
return _lableContent;
}
set
{
_lableContent = value;
OnPropertyChanged(nameof(LableContent));
}
}
public ICommand LoadedCommand { get; }
#endregion
#region Public Methods
public void ProcessMessages()
{
while (true)
{
Thread.Sleep(1000);
LableContent = "your value field";
}
}
#endregion
}