我是WPF的新手,对小项目有疑问。我正在构建一个测试器来模拟由UDP控制的设备。我有几个类将UDP实现为异步实现。我有主窗口代码隐藏轮询接收缓冲区的数据和更新。它奏效了,但非常笨重。所以我移动了EndReceiveFrom所在的异步接收中的所有代码。它更快,摆脱了民意调查。但我无法再访问窗口控件来更新它们。
如何从窗外访问控件?该窗口实例化运行它的UDP类,因此我可以在构造函数调用上传递内容。当然,我可以访问App。我知道我在这里遗漏了一些东西。
理查德
答案 0 :(得分:2)
过了一段时间 - 所以我不会提供太多的代码块 - 但听起来你可能想要应用MVC,或它的堂兄MVP或MVVM。不要过于担心它们的含义,但一般来说,它们会尝试定义View [您的窗口],Data [您的网络层结果]和Business [您的网络层]之间的关系。
在你的情况下,我会推荐MVVM。如果你谷歌它,你应该能够找到有关设计模式和应用方式的大量信息。再说一遍,不要过分夸大理论。只是一个假。
接下来,一些肉,
从概念上讲,您希望在“视图”中表示“数据”。在不担心视图的情况下,让我们首先封装您的数据。
// name is a little too general, so just rename it to something
// specific in your source.
public class NetworkViewModel
{
// enumerate your data here
public int Trouble { get; set; }
public int Tribbles { get; set; }
...
}
您的观点就是您的窗口。让您的视图实例化此“视图模型”的实例
public class MyNetworkMonitor
{
...
// advanced: if you were injecting this - say from another source
// or intended to replace the instance during runtime, there are
// ways to deal with that. for now, we presume one instance for
// application lifetime.
public NetworkViewModel ViewModel { get; set; }
public MyNetworkMonitor ()
{
ViewModel = new NetworkViewModel ();
}
...
}
并在您的Xaml中绑定到属性
// Xaml omitted, a limit to my memory :P
// but just regular binding to say ViewModel.Trouble
好的。因此,如果您的视图模型具有初始值,它将显示给绑定控件。不幸的是,如果视图模型属性更新,则无法告知绑定控件值已更改。呃,除非你实现了Wpf绑定寻找的通用接口,
public class NetworkViewModel : INotifyPropertyChanged
{
// defined by interface
public event PropertyChangedEventHandler PropertyChanged;
private int _trouble = 0;
public int Trouble
{
get { return _trouble; }
set
{
// 1. if value changes
if (_trouble != value)
{
_trouble = value;
// 2. inform whomever is listening!
if (PropertyChanged != null)
{
PropertyChanged (
this,
new PropertyChangedEventArgs ("Trouble"));
}
}
}
}
}
当然,你可以包装并做任何你喜欢的事情来简化语法,但是在模型方面你的基本实现是什么。
如果您要在窗口中按下按钮并增加ViewModel.Trouble,您会在绑定控件中看到实时更新。好哇!
然后剩下的就是将业务层(即您的网络层)连接到ViewModel。你可以通过多种方式实现这一目标。您可以将视图模型的实例传递到网络层,您可以让视图模型直接响应网络层上的事件 - 这完全取决于您。
现在,如果您继续这样做,它将无法正常工作。抱歉。现在,这不完全是我的错,你看到Wpf不喜欢任何人修改它的数据。更具体地说,任何可能影响Wpf控件的内容必须在拥有该控件的Gui线程上调用。正如您可能猜到的,您用于修改视图模型的线程源自网络中断和诸如此类的东西。网络线程。 Pleabs。 莫洛克。 Pah中!
无论如何,我离题了。对此有一种相对无痛的方式。当您检测到要报告的更改时,将更改分派给Gui线程。
someWpfControl.Dispatcher.Invoke (
DispatcherPriority.Normal,
new Action(
delegate()
{
ViewModel.Trouble = someNewValue;
});
但这有点无用,因为你的网络层不应该知道关于Wpf的任何信息。那么在ViewModel
中如何呢?...
// within property, after detecting change and
// testing for listeners
someWpfControl.Dispatcher.Invoke (
DispatcherPriority.Normal,
new Action(
delegate()
{
PropertyChanged (
this,
new PropertyChangedEventArgs ("Trouble"));
});
...
和以前一样,随意把它包装在其他任何地方。就像在辅助方法中一样。顺便说一句,'someWpfControl'可以成为窗口。所以你可以把它传递给ctor。我也强烈建议你选择“调用Dispatcher”的Google替代方案,因为可能有更聪明的方法,不涉及控件引用,在视图模型中进行大量剪切和粘贴等等。
只要Gui线程更新控件,您就可以执行任何操作:)
另外,我的伴侣和Wpf弟子肯特的无耻插件,他对Wpf的了解比我自己更多。 [http://kentb.blogspot.com/]
干杯:)