Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF视图在关闭时将ViewModel属性设置为null_C#_.net_Wpf_Mvvm - Fatal编程技术网

C# WPF视图在关闭时将ViewModel属性设置为null

C# WPF视图在关闭时将ViewModel属性设置为null,c#,.net,wpf,mvvm,C#,.net,Wpf,Mvvm,我有一个在GroupBox中显示用户控件的应用程序。要显示控件,我将绑定到主窗体的ViewModel中的属性,该属性返回要显示的ViewModel。我已经设置了DataTemplates,以便表单自动知道要使用哪个UserControl/视图来显示每个ViewModel 当我显示另一个UserControl时,我会保持上一个控件的ViewModel处于活动状态,但是WPF会自动放弃这些视图 我遇到的问题是,当视图关闭时,ViewModel中属性的任何双向绑定都会立即设置为null,因此当我再次显

我有一个在GroupBox中显示用户控件的应用程序。要显示控件,我将绑定到主窗体的ViewModel中的属性,该属性返回要显示的ViewModel。我已经设置了DataTemplates,以便表单自动知道要使用哪个UserControl/视图来显示每个ViewModel

当我显示另一个UserControl时,我会保持上一个控件的ViewModel处于活动状态,但是WPF会自动放弃这些视图

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

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

我的资源中的数据模板

<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");
    }
}
公共可观测收集监督员
{
得到
{
返回主管;
}
}
公共整数?选定的受监控ID
{
得到
{
返回所选的SupervisorID;
}
设置
{
selectedSupervisorID=值;
此。OnPropertyChanged(“SelectedSupervisorID”);
}
}

你知道如何阻止我的视图清空我的ViewModels中的值吗?我在想,也许我需要在视图关闭之前将其DataContext设置为null,但我不确定如何按照当前绑定的方式进行操作。

我找到了一个可能的解决方案,但我真的不喜欢它

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

因此,当DataContext发生更改时,如果新上下文为null,那么我将删除ComboBox上的相关绑定,如下所示:

private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue == null)
    {
        SupervisorDropDown.ClearValue(ComboBox.SelectedValueProperty);
    }
}
我不太喜欢这种方法,因为这意味着我必须记住对我使用的每个数据绑定控件都要这样做。如果有一种方法,我可以让每个UserControl在关闭时自动删除它们的绑定,那就可以了,但我想不出任何方法来做到这一点

另一个选择可能是重新构造我的应用程序,这样视图就不会被破坏,直到ViewModels被破坏——这将完全避免这个问题

当我显示不同的 UserControl,我保留的是 上一个控件处于活动状态,但 视图将被自动丢弃 WPF

我遇到的问题是 当视图关闭时,任何双向 中的属性的绑定 ViewModel会立即设置为null, 所以当我显示ViewModel时 同样,所有的值都被设置好了 在UI中设置为null


我不是WPF或MVVM方面的专家,但这方面的某些内容听起来不太正确。我很难相信WPF对视图的处理导致了您的问题。至少,在我有限的经验中,我从未发生过这样的事情。我怀疑罪魁祸首可能是视图模型中的代码,也可能是替换出哪个视图模型用于datacontext的代码。

在尝试通过各种方式停止空设置后,我放弃了,而是让它按如下方式工作。在关闭视图之前,我将ViewModel设置为只读。我在ViewModelBase类中实现了这一点,其中添加了IsReadOnly布尔属性。然后在ViewModelBase.SetProperty()中(见下文),当IsReadOnly为true时,我忽略任何属性更改

    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;
    }
protected bool SetProperty(ref T backingField,T value,string propertyName)
{
var change=!IsReadOnly&&!EqualityComparer.Default.Equals(backingField,value);
如果(更改){
backingField=值;
OnPropertyChanged(propertyName);
}
回报变化;
}

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

我也有同样的问题。对我有效的方法是从我选择的ValueBindings中删除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>

更新资源记录器显式设置为LostFocus

如果视图正在关闭并将其数据设置为null,则它对viewmodel中的数据没有影响

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

我也遇到了同样的问题。将可视子对象的DataContext设置为null可以部分解决此问题。隐藏视图而不是破坏视图没有任何区别。我仍在寻找一个完整的解决方案。
TabCollection.Add(new WelcomeTabViewModel());
TabCollection.Add(new UserSecurityViewModel(_userService, _bpcsUsersLookup));
TabCollection.Add(new PackItemRegisterViewModel(_packItemService, _itemClassLookup));
SelectedTabIndex = 0;
<ComboBox Name="SupervisorDropDown" ItemsSource="{Binding Path=Supervisors}" DisplayMemberPath="sgSupervisor" 
SelectedValuePath="idSupervisor" 
SelectedValue="{Binding Path=SelectedSupervisorID, UpdateSourceTrigger=LostFocus}" />