wpf - 当代码从主 UI 线程移动到类时,UI 组件在当前上下文中不存在
问题描述
我目前有在 MainWindow.xaml.cs 中实现的工作代码,我正试图移动到一个类,这给了我一个错误,即我的 UI 标签在当前上下文中不存在。
这是在 MainWindow 中工作的代码:
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 以外的其他类访问 mylbl,因为它是在那里定义的。您可以实现 MVVM 并将内容属性绑定到视图模型中的字符串并更新内容。
或将您的业务逻辑分离为单独的类并将其公开给 MyWindow.Xaml.cs。
您可以有一个在 RX 中返回“值”的公共方法。您可以通过访问此方法更新 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);
}
}
}
正如 Clemens 所建议的,我正在以 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>
我将 LableContent 字符串属性绑定到 Label 的 Content 属性。并将顶部的数据内容设置为我的视图模型。此外,为了将事件绑定到命令,我使用了交互 dll。
ViewModel 看起来像这样。
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
}
我已将 ICommand 实现用于命令。我也使用 INotifyPropertyChanged 进行绑定。
我假设您了解以下主题,如果没有,在这些方面的堆栈溢出方面有很多帮助
- INotifyProertyChanged
- 事件到命令绑定
- 什么是数据上下文以及如何设置数据上下文
- 什么是 ICommand 和实现 ICommand
推荐阅读
- reactjs - ReactJS 路由模糊路由匹配
- prestashop - 来自特定类别 prestashop 的新产品
- angularjs - 如何在 Angular Js 中使用两个不同的文件输入上传两个文件?
- django - 如何在 Vue JS 模板中检查 Django 权限
- node.js - Node.js readUIntBE 任意大小限制?
- javascript - Access 和 Office 加载项复选框已选中状态
- kotlin - 使用 Mockito 在 Kotlin 中模拟自动生成的设置器
- javascript - 如何使用 JS 通过 chrome 扩展在本地保存用户访问的 url?
- c# - Linux Debian 多语言上的 Mono C# 应用程序
- php - WordPress:随机显示 4 个类别和 3 个最后的帖子