简体   繁体   English

如何将 mdiContainer 子项绑定到 viewModel 属性?

[英]How to bind mdiContainer children to viewModel property?

I am using CodePlex wpfmdi container for my WPF application.我正在为我的 WPF 应用程序使用 CodePlex wpfmdi 容器。

I need to bind MdiContainer 's children to a viewModel property.我需要将MdiContainer的孩子绑定到 viewModel 属性。

<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite" Children="{Binding Path=Container}"/>

If I do this I am getting this error:如果我这样做,我会收到此错误:

Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.Collections.ObjectModel.ObservableCollection`1[WPF.MDI.MdiChild]' 'System.Windows.Data.Binding' 类型的 Object 无法转换为'System.Collections.ObjectModel.ObservableMFChild'1 类型

This is what the Children property in MdiContainer looks like:这是MdiContainer中的Children属性的样子:

public ObservableCollection<MdiChild> Children { get; set; }

What am I doing wrong?我究竟做错了什么?

The Children property is not exposed as a dependency property, which means you cannot bind it. Children属性不作为依赖属性公开,这意味着您无法绑定它。 Furthermore, it is initialized once in the constructor of the MdiContainer type and then a handler is added to the CollectionChanged event of the underlying ObservableCollection<MdiChild> .此外,它在MdiContainer类型的构造函数中初始化一次,然后将处理程序添加到底层ObservableCollection<MdiChild>CollectionChanged事件。 It is never updated or removed.它永远不会更新或删除。

Therefore, although the Children property has a setter, it will break the control if you use it to set a different collection.因此,虽然Children属性有一个 setter,但如果您使用它来设置不同的集合,它将破坏控件。 This also implies that you cannot simply create attached properties to expose a bindable Children dependency property.这也意味着您不能简单地创建附加属性来公开可绑定的Children依赖项属性。

Apart from that, MdiChild is a Control , so it actually contradicts the purpose of your view model.除此之外, MdiChild是一个Control ,因此它实际上与您查看 model 的目的相矛盾。 If you expose a collection of user interface controls from your view model this conflicts with the MVVM pattern.如果您从视图 model 公开一组用户界面控件,则这与 MVVM 模式冲突。 View models should not have any knowledge about the view.视图模型不应该对视图有任何了解。 However, the MDI controls do not seem to follow the usual WPF practices for custom controls, so there is not much room for improvement here, data templating is not supported, the MdiContainer is a UserControl and there are very limited dependency properties.但是,MDI 控件似乎没有遵循自定义控件通常的 WPF 做法,因此这里没有太大的改进空间,不支持数据模板, MdiContainer是一个UserControl ,依赖属性非常有限。

If you really want to continue working with this control with your current approach, you could:如果您真的想继续使用当前方法使用此控件,您可以:

  • Create a custom attached behavior to synchronize your view model collection with the Children collection of the MdiContainer and vice-versa, see XAML behaviors in WPF .创建自定义附加行为以将您的视图 model 集合与MdiContainerChildren集合同步,反之亦然,请参阅WPF 中的 XAML 行为

  • Use the Loaded event to assign the Children collection to your view model property.使用Loaded事件将Children集合分配给您的视图 model 属性。

     <mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite" Loaded="MdiContainer_OnLoaded">
     private void MdiContainer_OnLoaded(object sender, RoutedEventArgs e) { var mdiContainer = (MdiContainer)sender; var dataContext = (Main)mdiContainer.DataContext; if (dataContext == null) return; dataContext.Children = mdiContainer.Children; }
  • Use an EventTrigger on the Loaded event with a custom trigger action that sets the Children collection.Loaded事件使用EventTrigger ,并使用设置Children集合的自定义触发器操作。 This is just a different variant of the previous approach that does not require code-behind.这只是先前方法的不同变体,不需要代码隐藏。

    The new XAML behaviors for WPF package, which replaces the legacy Blend behaviors from the System.Windows.Interactivity namespace already includes such a trigger action. The new XAML behaviors for WPF package, which replaces the legacy Blend behaviors from the System.Windows.Interactivity namespace already includes such a trigger action. Install the Microsoft.Xaml.Behaviors.Wpf NuGet package and use this:安装Microsoft.Xaml.Behaviors.Wpf NuGet ZEFE90A8E604A77640E8ZD03 和使用这个:

     <mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite"> <behaviors:Interaction.Triggers> <behaviors:EventTrigger EventName="Loaded"> <behaviors:ChangePropertyAction TargetObject="{Binding DataContext, ElementName=Container}" PropertyName="Children" Value="{Binding Children, ElementName=Container}"/> </behaviors:EventTrigger> </behaviors:Interaction.Triggers> </mdi:MdiContainer>

Note that with these approaches, you either synchronize to your own collection or you work directly with the collection of the MdiContainer that you passed to your view model.请注意,使用这些方法,您可以同步到自己的集合,也可以直接使用传递给视图 model 的MdiContainer的集合。 These are only workarounds.这些只是解决方法。 If you would want to implement this in a clean and MVVM compliant way, I think you would need to extend or fix the control itself, which is rather costly and not recommendable, since it seems to be dead anyway.如果您想以干净且符合 MVVM 的方式实现此功能,我认为您需要扩展或修复控件本身,这是相当昂贵且不推荐的,因为它似乎已经死了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM