我有这个有趣的案例: 一个相当大的应用程序的页面有它自己的ViewModel。部分数据来自完全不同的经理类。我的ViewModel可以访问这些数据。每次经理类更新一个值,它都会发送一个调解器消息。 ViewModel获取消息并调用OnPropertyChanged(nameof(ManagerdataData))
。 ManagerData财产只有一个获得者得到Manager.Data
。所以页面会更新它的内容。该系统目前运作良好。ViewModel的第二个视图不刷新
现在我打开一个MessageBox事物(这是一个System.Window
),得到MessageBox.DataContext = this.ViewModel
。对于用户界面,它也适用。我的所有ManagerData都被加载并显示在differend Bindings中。但是: OnPropertyChanged似乎没有效果。 页面每次都会刷新这个特殊的Mediator-Message来自Manager,然后ViewModel会触发OnNotificationChanged,绑定值会重新加载并从Manager中获取新数据。但是MessageBox不具有相同的ViewModel。
有没有人有这样的想法?
我想,也许这是我的ViewModel的另一个实例(副本)。所以我问是否显示一个弹出窗口,获取正确类型的最顶层窗口并尝试调用包含这些OnNotificationChanged值的方法。首先它因为我错误的线程而崩溃。使用调度程序会导致整个应用程序冻结。
有什么想法?复制代码...不容易,因为该项目是相当大的...
编辑: 好了,所以这里的代码:
视图模型:
// Inside the constructor. Registers for Mediator-message. The manager sends it when a value is set.
Mediator.Register(MediatorMessage.BackendServerCheckRefreshed,() => RefreshServerCheckUi());
// Method of the Mediator Message
public void RefreshServerCheckUi()
{
OnPropertyChanged(nameof(BackendServers));
OnPropertyChanged(nameof(BackendServersCommonStatus));
}
// Properties that get stuff from the manager
public BackendServerStatus BackendServersCommonStatus
{
get
{
return backendServerManager.CommonStatus;
}
}
public BackendServer[] BackendServers
{
get
{
return backendServerManager.BackendServers;
}
}
这样做的UI页面:
<!--Style definition-->
<Style TargetType="Image" x:Key="BackendServerAvailability">
<Style.Triggers>
<DataTrigger Binding="{Binding BackendServersCommonStatus}"
Value="{x:Static server:BackendServerStatus.NotAvailable}">
<Setter Property="Source" Value="inactive.png" />
</DataTrigger>
<DataTrigger Binding="{Binding BackendServersCommonStatus}"
Value="{x:Static server:BackendServerStatus.Available}">
<Setter Property="Source" Value="active.png" />
</DataTrigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Source" Value="default.png" />
</Style.Setters>
</Style>
<!--Image-->
<Image Style="{StaticResource BackendServerAvailability}" />
这个绑定工程。当值刷新时,它发送调解器消息,这调用OnPropertyChanged
,然后图标获取其图像。
现在棘手的问题:
// This is how I call the MessageBox from the ViewModel
this.MessageService.ShowBackendServerCheckInfo(this);
的MessageBoxService:
// All MessageBoxes are created like this.
public void ShowBackendServerCheckInfo(ViewModel viewModel)
{
Action action = new Action(() =>
{
var args = new MessageBoxEventArgs()
{
View = new BackendServerCheckMessageBox(),
ViewModel = viewModel
};
OnNewMessageBox(this, args);
});
this.ShowMessageBox(action);
}
// And then called like this:
private void ShowMessageBox(Action action)
{
/* We need to create the view in the same thread as main application. */
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, action);
}
终于在MainWindow.xaml.cs:
private async void MessageService_OnNewMessageBox(object sender, MessageBoxEventArgs e)
{
// Some Semaphore work here..
var messageBox = e.View;
messageBox.DataContext = e.ViewModel;
messageBox.Owner = this;
messageBox.ShowDialog();
// Release Semaphore
}
MessageBox的UI:
<ItemsControlItemsSource="{Binding BackendServers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Stackpanel>
<TextBlock Text="{Binding Url}" />
<TextBlock Text="{Binding Port}" />
<Image Style="{StaticResource BackendServerAvailability}" />
</Stackpanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!--Buttons-->
<Stackpanel>
<Button Style="{StaticResource SimpleButtonStyle}"
Command="{Binding CloseBackendServerCheckCommand}"
CommandParameter="{Binding ElementName=BackendServerMsgBox}">
<TextBlock Foreground="White" Margin="2" FontSize="14"
Text="{x:Static const:Resources.ButtonOk}" />
</Button>
<Button Style="{StaticResource SimpleButtonStyle}"
Command="{Binding RestartBackendServerCheckCommand}">
<TextBlock Foreground="White" Margin="2" FontSize="14"
Text="{x:Static const:Resources.ButtonRefresh}" />
</Button>
</StackPanel>
所以这是所有相关的代码。当绑定不起作用时,我根本没有任何价值,按钮也不起作用。关闭按钮将其作为参数发送其Window
,然后args-Window-Object将被关闭。如果绑定和东西不起作用,什么都不会发生。 我修好了。现在我看到了我所有的价值。但是,当backgroundcheck发送一条消息,指出某个服务器不可用时,Popup-Image在应用程序图像不会刷新时不会刷新。
我的猜测是,通过所有的东西作为EventArgs可能会做一些副本,所以绑定到正确的ViewModel实例会丢失...所以我会为这个弹出窗口,并直接在我的ViewModel创建它。无论如何,它比任何“平常”的弹出式菜单都要多,只是向你抛出一些东西,而你用“好吧”点击它。在这种情况下更复杂。
编辑2: Aaaand直接从ViewModel调用MessageBox并没有改变一件事。它不起作用。这是一个有多个绑定视图的问题吗?
EDIT3: 好吧,它实际上不工作,当我有弹出和重新设置的DataContext从视图模型的实例。所以我必须找到一个很好的方式来获得或保持实例...
视觉工作室的输出窗口可能会给你我想的答案。没有足够的代码来复制行为,我们无法帮助您。 – nkoniishvt
什么可能在输出窗口中?我认为这可能是更多的理论问题:你认为viewmodel实例只是复制到datacontext? – ecth
*如果*您已准确地表示将视图模型分配给MessageBox.DataContext的方式,则复制事件似乎不太可能。但是对于那些说“实际上我不会告诉你我的任何代码,请重新构造它所做的一切”的人来说,这很难说。发生了什么显然是可能的,因为它正在发生。我的第一个猜测是,你的问题在于你完全排除的东西,因为你知道它不可能是这样。这可能不是异国情调。这可能是一个常见的错误,您可以通过遵循从点A到点Z的所有内容来找到。 –