【问题标题】:Changing the ContentControl binding results in a null DataContext更改 ContentControl 绑定会导致空 DataContext
【发布时间】:2020-03-19 19:08:45
【问题描述】:

也许你们中的一个人可以就以下问题启发我。 我使用列表框作为在 2 个视图模型之间导航的一种方式。

<Window x:Class="MyWPFApp.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:cal="http://www.caliburnproject.org">

  <Grid Background="White">
     <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="8*"/>
     </Grid.ColumnDefinitions>
     <ListBox Grid.Column="0" cal:Message.Attach="[Event SelectionChanged] 
= [Action onViewSelectionChange($this.SelectedItem.Text)]">
        <TextBlock Text="FirstView"/>
        <TextBlock Text="SecondView"/>
     </ListBox>
        <ContentControl Grid.Column="1" Content="{Binding MyViewModel}"/>
  </Grid>

namespace MyWPFApp
{
    public class ShellViewModel : Caliburn.Micro.PropertyChangedBase, IShell
   {
      private object _vm;

      public object MyViewModel
      {
         get { return _vm; }
         set { _vm = value; NotifyOfPropertyChange(() => MyViewModel); }
      }

      public FirstViewModel vm1;
      public SecondViewModel vm2;



      public ShellViewModel()
      {
         vm1 = new FirstViewModel();
         vm2 = new SecondViewModel();
         MyViewModel = vm1;

      }

      public void onViewSelectionChange(string str)
      {

         switch (str)
         {
            case "FirstView":
               MyViewModel = vm1;
               break;
            case "SecondView":
               MyViewModel = vm2;
               break;
            default:
               break;

         }
      }
   }
}

我创建了 2 个数据模板来将视图模型与其视图相关联

<Application x:Class="MyWPFApp.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-MyWPFApp">
  <Application.Resources>
  <ResourceDictionary>
     <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary>
           <local:AppBootstrapper x:Key="bootstrapper" />
        </ResourceDictionary>
     </ResourceDictionary.MergedDictionaries>
     <DataTemplate DataType="{x:Type local:FirstViewModel}">
        <Grid>
           <local:FirstView></local:FirstView>
        </Grid>
     </DataTemplate>
     <DataTemplate DataType="{x:Type local:SecondViewModel}">
        <Grid>
           <local:SecondView></local:SecondView>
        </Grid>
     </DataTemplate>
  </ResourceDictionary>
  </Application.Resources>
  </Application>

FirstView 实际上具有绑定到 FirstViewModel 中的属性的控件

   <UserControl x:Class="MyWPFApp.FirstView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:local="clr-namespace:MyWPFApp"
            xmlns:cal="http://www.caliburnproject.org"
            mc:Ignorable="d" 
            d:DesignHeight="300" d:DesignWidth="300">
  <Grid Background="Aquamarine">
     <ListBox SelectedIndex="{Binding SelectedIndex}" 
              SelectedItem="{Binding SelectedItem}"
              cal:Message.Attach="[Event SelectionChanged]=[Action OnLBSelectionChanged($source)]">
        <ListBoxItem>apple</ListBoxItem>
        <ListBoxItem>orange</ListBoxItem>
        <ListBoxItem>pear</ListBoxItem>
     </ListBox>
  </Grid>

using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyWPFApp
{
   public class FirstViewModel : PropertyChangedBase
   {

      private int _selectedindex;

      public int SelectedIndex
      {
         get { return _selectedindex; }
         set { _selectedindex = value; NotifyOfPropertyChange(() => SelectedIndex); }
      }


      private string _selecteditem;

      public string SelectedItem
      {
         get { return _selecteditem; }
         set { _selecteditem = value; NotifyOfPropertyChange(() => SelectedItem); }
      }



      public FirstViewModel()
      {
      }


      public void OnLBSelectionChanged(System.Windows.Controls.ListBox lb)
      {
         if(lb.DataContext == null)
         {
            Debug.WriteLine("The DataContext is null");
         }

      }

   }
}

SecondView 不包含任何控件。

当 ShellView 列表框选择从 FirstView 变为 SecondView 时,我注意到 FirstView ListBox DataContext 变为 null。

  public void OnLBSelectionChanged(System.Windows.Controls.ListBox lb)
  {
     if(lb.DataContext == null)
     {
        Debug.WriteLine("The DataContext is null");
     }

  }

我宁愿不必处理寻找空 DataContext 的选择更改。相反,我想知道实际发生了什么。 谢谢。

【问题讨论】:

    标签: c# wpf mvvm caliburn


    【解决方案1】:

    发生这种情况的原因是当ContentControlContent 属性通过数据绑定设置为FirstViewModel 时,WPF 隐式连接了FirstViewDataContext

    一旦绑定更改为 SecondViewModelFirstViewModel 就会超出范围,因此 WPF 会自行清理,删除 FirstViewModelFirstView 及其隐式 DataContext 绑定。

    我希望这会有所帮助。

    【讨论】:

    • 我对这个问题的解决方案是响应选择更改事件(当 DataContext 变为 null 时发生)并检查 null DataContext。有没有办法防止 DataContext 变为空?例如改变 ContentControl 的可见性,而不是在 ViewModel 之间切换
    • 如果你想让视图和视图模型都保持活力,你需要改变你的做事方式。你不能用你当前的代码完成你想要的。我建议只更新你的两个视图和视图模型,并在代码中连接它们的数据上下文。然后在它们之间切换。
    • Caliburn Micro 可以根据您的用例使用Conductor.Collection.OneActive.AllActive 来执行此操作。您是否查看过框架中这些类型的生命周期事件?
    猜你喜欢
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 2013-11-29
    • 2011-01-07
    相关资源
    最近更新 更多