2009-06-16 110 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}" /> 
相關問題