【发布时间】:2009-12-16 20:54:14
【问题描述】:
更新(2009 年 12 月 17 日):现在反映了我取得的最新进展。
这是我和同事在 Silverlight 3.0 中使用 Prism 和 MVVM 开发的第一个应用程序。我正在为该项目开发一个外壳/框架,该项目将包含一个可以添加到“工作区”的“插件”列表。
插件在其特定的 PRISM IModule.Initialize() 方法中注册到 WorkSpaceManager 类,如下所示:
workspace.RegisterPlugin(new PluginInfo() { Name = "MyPlugin", ViewType = typeof(MyPluginView), SettingsViewType = null });
RegisterPlugin() 方法只是将 PluginInfo 对象添加到以“Name”属性为键的字典中。然后,当我想向工作区添加插件时,我执行以下操作:
workspace.AddPluginToWorkspace("MyPlugin");
WorkspaceManager 类的 AddPluginToWorkspace 方法如下所示:
public void AddPluginToWorkspace(string pluginName)
{
if (AvailablePlugins.ContainsKey(pluginName))
{
PluginInfo pi = AvailablePlugins[pluginName];
WorkspacePlugin wsp = new WorkspacePlugin();
// Create the View
wsp.View = (Control)this.unityContainer.Resolve(pi.ViewType);
wsp.Name = pi.Name;
// Wire up the CloseCommand to WorkspaceManager's PluginClosing handler
wsp.CloseCommand = new DelegateCommand<WorkspacePlugin>(this.PluginClosing);
// Add the plugin to the active plugins (modules) collection
this.modules.Add(wsp);
// FIX: This should notify anyone listening that the ActivePlugins have changed. When enabled, this causes the same error that will be mentioned further on when attempting to close a plugin.
//this.eventAggregator.GetEvent<ActivePluginsChanged>().Publish(wsp);
}
}
Workspace ViewModel 只是公开 WorkspaceManager 服务的模块集合,它是 Workspace View 的数据上下文,如下所示:
<Grid x:Name="LayoutRoot"
Background="White">
<ListBox x:Name="ModuleListBox"
Grid.Row="1"
rgn:RegionManager.RegionName="Workspace"
Background="Yellow"
ItemsSource="{Binding Plugins}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Template>
<ControlTemplate>
<Grid x:Name="ListBoxGrid">
<ItemsPresenter></ItemsPresenter>
</Grid>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black"
BorderThickness="2"
Margin="0"
Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="5"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width=".05*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="X"
HorizontalAlignment="Right"
Grid.Column="1"
cmd:Click.Command="{Binding CloseCommand}"
cmd:Click.CommandParameter="{Binding}"></Button>
</Grid>
<Border BorderBrush="Black"
BorderThickness="2"
Margin="0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.Row="1">
<tk:Viewbox Stretch="Uniform"
StretchDirection="Both">
<ContentControl Content="{Binding View}"></ContentControl>
</tk:Viewbox>
</Border>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
请注意绑定到 WorkspacePlugin 的“View”属性的 Content 控件以及将 Click.Command 绑定到“CloseCommand”的 Button。这是我最初被卡住的地方,但在大多数情况下,这是可行的。插件的视图加载在其他控件中,我仍然能够将关闭命令(以及稍后添加的其他命令)绑定到底层模型。
现在的问题是,每当我单击关闭按钮并从模块集合中删除 WorkspacePlugin 时,就会在 ViewModel 上触发一个属性更改事件,让列表框知道要更新我得到以下错误(如果我取消对上面“FIX”注释下方的行的注释,也会发生这种情况:
System.ArgumentException:值不在预期范围内。 在 MS.Internal.XcpImports.CheckHResult(UInt32 小时) 在 MS.Internal.XcpImports.SetValue(INativeCoreTypeWrapper obj,DependencyProperty 属性,DependencyObject doh) 在 MS.Internal.XcpImports.SetValue(INativeCoreTypeWrapper doh,DependencyProperty 属性,对象 obj) 在 System.Windows.DependencyObject.SetObjectValueToCore(DependencyProperty dp,对象值) 在 System.Windows.DependencyObject.RefreshExpression(DependencyProperty dp) 在 System.Windows.Data.BindingExpression.RefreshExpression() 在 System.Windows.Data.BindingExpression.SendDataToTarget() 在 System.Windows.Data.BindingExpression.SourceAquired() 在 System.Windows.Data.BindingExpression.DataContextChanged(对象 o,DataContextChangedEventArgs e) 在 System.Windows.FrameworkElement.OnDataContextChanged(DataContextChangedEventArgs e) 在 System.Windows.FrameworkElement.OnTreeParentUpdated(DependencyObject newParent,布尔 bIsNewParentAlive) 在 System.Windows.DependencyObject.UpdateTreeParent(IManagedPeer oldParent,IManagedPeer newParent,布尔 bIsNewParentAlive,布尔 keepReferenceToParent) 在 MS.Internal.FrameworkCallbacks.ManagedPeerTreeUpdate(IntPtr oldParentElement,IntPtr parentElement,IntPtr childElement,字节 bIsParentAlive,字节 bKeepReferenceToParent)
根据我通过在线查看收集到的信息,这通常意味着已经添加到可视化树中的可视化元素正在尝试再次添加。这种原因是因为如果我只显示 1 个插件并关闭它,它就会消失并且没有错误。我相当肯定该错误是由于 WorkspacePlugin.View 属性是一个可视控件,并且绑定更新正在尝试将其重新添加到可视树中。
我怎样才能解决这个问题或在没有错误消息的情况下达到预期的结果?
【问题讨论】:
-
我不明白您为什么要使用 Prism 区域并绑定到 ItemsSource?为什么不直接说 regionManager.RegisterViewWithRegion("Workspace", typeof(MyPlugin)) 让你的模块贡献插件呢?这里有些奇怪。
-
实际上这可能是问题所在...我将把它作为答案,看看会发生什么:)
-
这是使用区域管理器缓冲您的事情之一(而不是绑定到视图集合)。您仍然在混合一些不必要的东西。如果我有时间的话,我今晚会试着为你写一个样本。
标签: c# silverlight mvvm prism