2009-06-16 108 views
6

我有一个应用程序,我在GroupBox中显示UserControls。为了显示控件,我绑定了主窗体的ViewModel中的一个属性,该窗体返回一个ViewModel来显示。我已经设置了DataTemplates,以便表单自动知道使用哪个UserControl/View来显示每个ViewModel。WPF View在关闭时将ViewModel属性设置为null

当我显示一个不同的UserControl时,我保持前一个控件的ViewModel处于活动状态,但视图被WPF自动丢弃。

我遇到的问题是,当视图关闭时,对ViewModel中的属性的任何双向绑定立即设置为null,因此当我再次显示ViewModel时,所有的值都刚刚设置在UI中为null。

我认为这是因为作为View关闭的一部分,它会处理和清除它所包含的控件中的任何值,并且由于绑定已就位,它们也向下传播到ViewModel。

的DataTemplates在我的资源

<DataTemplate DataType="{x:Type vm:HomeViewModel}"> 
    <vw:HomeView /> 
</DataTemplate> 
<DataTemplate DataType="{x:Type vm:SettingsViewModel}"> 
    <vw:SettingsView /> 
</DataTemplate> 
<DataTemplate DataType="{x:Type vm:JobListViewModel}"> 
    <vw:JobListView /> 
</DataTemplate> 

代码用于显示用户控制我在视图中的一个正在结合的控制的

<GroupBox> 
    <ContentControl Content="{Binding Path=RightPanel}" /> 
</GroupBox> 

实施例:

<ComboBox Name="SupervisorDropDown" ItemsSource="{Binding Path=Supervisors}" DisplayMemberPath="sgSupervisor" 
      SelectedValuePath="idSupervisor" SelectedValue="{Binding Path=SelectedSupervisorID}" /> 

和相关的ViewModel属性:

public ObservableCollection<SupervisorsEntity> Supervisors 
    { 
     get 
     { 
      return supervisors; 
     } 
    } 

public int? SelectedSupervisorID 
{ 
    get 
    { 
     return selectedSupervisorID; 
    } 
    set 
    { 
     selectedSupervisorID = value; 
     this.OnPropertyChanged("SelectedSupervisorID"); 
    } 
} 

任何想法如何停止我的视图null值我的ViewModels中的值?我在想,也许我需要将View的DataContext在关闭之前设置为null,但我不确定如何通过当前绑定的方式来解决此问题。

回答

0

我发现了一种可能的解决方案,但我真的不喜欢它。

事实证明DataContext IS已被设置为null,但这没有帮助。它发生在属性设置为空之前。看起来发生的情况是数据绑定在UserControl/View处理自身之前未被删除,因此当控件被删除时,空值向下传播。

所以当DataContext的变化,如果新的上下文为null,则我删除的组合框的相关绑定,如下所示:

private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
{ 
    if (e.NewValue == null) 
    { 
     SupervisorDropDown.ClearValue(ComboBox.SelectedValueProperty); 
    } 
} 

我不是这种方法的大风扇,因为它意味着我必须记得为我使用的每个数据绑定控件执行此操作。如果有一种方法,我可以让每个UserControl在关闭的时候自动删除它们的绑定,但我想不出有什么办法可以做到这一点。

另一种选择可能是重构我的应用程序,以便视图不会被破坏,直到ViewModels做 - 这将完全避开这个问题。

+0

我遇到同样的问题。将Visual儿童的DataContext设置为null部分解决了它。隐藏视图而不是销毁视图没有任何区别。我仍在寻找完整的解决方案。 – HappyNomad 2010-11-23 19:00:29

0

当我显示不同的用户控件 ,我保持 视图模型的前一控制活性,但 视图是由 WPF自动丢弃。

说我有问题是,当 视图关闭,任何双向 绑定在 视图模型属性被立即设置为null, ,所以当我显示视图模型 再次全部在UI中将值设置为空值 。

我并不是WPF或MVVM方面的专家,但有关这方面的信息听起来不对。我很难相信WPF处理视图会导致你的问题。至少,在我有限的经历中,我从未有过这样的事情发生过。我怀疑罪魁祸首是在视图模型或视图模型被用于的datacontext代码swaping出或者代码。

0

试图阻止通过各种方式零设定后,我放弃了,而不是得到它的工作如下。在关闭其视图之前,我将ViewModel设置为只读。我在ViewModelBase类中实现了这一点,我添加了一个IsReadOnly布尔属性。然后在ViewModelBase.SetProperty()(见下文),我忽略任何属性发生变化时IsReadOnly是真实的。

protected bool SetProperty<T>(ref T backingField, T value, string propertyName) 
    { 
     var change = !IsReadOnly && !EqualityComparer<T>.Default.Equals(backingField, value); 

     if (change) { 
      backingField = value; 
      OnPropertyChanged(propertyName); 
     } 
     return change; 
    } 

它似乎是这样工作,虽然我仍然想知道更好的解决方案。

0

我有同样的问题。什么工作对我来说是从我SelectedValueBindings去除UpdateSourceTrigger =的PropertyChanged。的PropertyChanged UpdateSourceTriggers似乎火在关闭的意见的绑定属性,当您使用模式:

<!--Users DataGrid--> 
<DataGrid Grid.Row="0" ItemsSource="{Binding DealsUsersViewSource.View}" 
    AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="False" 
    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
    <DataGrid.Resources> 
     <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#FFC5D6FB"/> 
    </DataGrid.Resources> 
    <DataGrid.Columns> 

      <!--Username Column--> 
      <DataGridComboBoxColumn 
      SelectedValueBinding="{Binding Username}" Header="Username" Width="*"> 
       <DataGridComboBoxColumn.ElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding DataContext.DealsUsersCollection.ViewModels, 
          RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
         <Setter Property="SelectedValuePath" Value="Username"/> 
         <Setter Property="DisplayMemberPath" Value="Username"/> 
        </Style> 
       </DataGridComboBoxColumn.ElementStyle> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding DataContext.BpcsUsers, 
          RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
         <Setter Property="SelectedValuePath" Value="Description"/> 
         <Setter Property="DisplayMemberPath" Value="Description"/> 
         <Setter Property="IsEditable" Value="True"/> 
        </Style> 
       </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 

      <!--Supervisor Column--> 
      <DataGridComboBoxColumn 
      SelectedValueBinding="{Binding Supervisor}" Header="Supervisor" Width="*"> 
       <DataGridComboBoxColumn.ElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding DataContext.DealsUsersCollection.ViewModels, 
          RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
         <Setter Property="SelectedValuePath" Value="Username"/> 
         <Setter Property="DisplayMemberPath" Value="Username"/> 
        </Style> 
       </DataGridComboBoxColumn.ElementStyle> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding DataContext.BpcsUsers, 
          RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
         <Setter Property="SelectedValuePath" Value="Description"/> 
         <Setter Property="DisplayMemberPath" Value="Description"/> 
         <Setter Property="IsEditable" Value="True"/> 
        </Style> 
       </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 

      <!--Plan Moderator Column--> 
      <DataGridCheckBoxColumn Binding="{Binding IsPlanModerator}" Header="Plan Moderator?" Width="*"/> 

      <!--Planner Column--> 
      <DataGridCheckBoxColumn Binding="{Binding IsPlanner}" Header="Planner?" Width="*"/> 

    </DataGrid.Columns> 
</DataGrid> 

容器视图:

<!--Pre-defined custom styles--> 
<a:BaseView.Resources> 

    <DataTemplate DataType="{x:Type vm:WelcomeTabViewModel}"> 
     <uc:WelcomeTabView/> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type vm:UserSecurityViewModel}"> 
     <uc:UserSecurityView/> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type vm:PackItemRegisterViewModel}"> 
     <uc:PackItemsRegisterView/> 
    </DataTemplate> 

</a:BaseView.Resources> 

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="30"/> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="30"/> 
    </Grid.ColumnDefinitions> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="30"/> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="30"/> 
    </Grid.RowDefinitions> 

    <TabPanel Grid.Column="1" Grid.Row="1"> 
     <TabControl TabStripPlacement="Top" ItemsSource="{Binding TabCollection}" SelectedIndex="{Binding SelectedTabIndex}" 
        DisplayMemberPath="DisplayName" MinWidth="640" MinHeight="480"/> 
    </TabPanel> 

</Grid> 

集装箱视图模型:

TabCollection.Add(new WelcomeTabViewModel()); 
TabCollection.Add(new UserSecurityViewModel(_userService, _bpcsUsersLookup)); 
TabCollection.Add(new PackItemRegisterViewModel(_packItemService, _itemClassLookup)); 
SelectedTabIndex = 0; 
0

设置UpdateSourceTrigger明确到引发LostFocus

如果视图被关闭,并将其数据为空,它在视图模型上的数据没有影响。

<ComboBox Name="SupervisorDropDown" ItemsSource="{Binding Path=Supervisors}" DisplayMemberPath="sgSupervisor" 
SelectedValuePath="idSupervisor" 
SelectedValue="{Binding Path=SelectedSupervisorID, UpdateSourceTrigger=LostFocus}" /> 
相关问题