简体   繁体   English

使用TabControl和MVVM时绑定丢失

[英]Binding lost when using TabControl and MVVM

I still consider myself a beginner when it comes to MVVM and I am having an issue with a binding in a TabControl. 当我谈到MVVM时,我仍然认为自己是初学者,而我在TabControl中遇到绑定问题。 My application allows the user to create nations and states, input some information and then save them to a database. 我的应用程序允许用户创建国家和州,输入一些信息,然后将它们保存到数据库中。 Below is a descriptions of how my application is structured: 以下是我的应用程序结构的描述:

The base ViewModel/View is called ApplicationViewModel/ApplicationView. 基本ViewModel / View称为ApplicationViewModel / ApplicationView。 The ApplicationViewModel has an ObservableCollection called Tabs consisting of one AllNationsViewModel and one AllStatesViewModel. ApplicationViewModel有一个名为Tabs的ObservableCollection,它包含一个AllNationsViewModel和一个AllStatesViewModel。 This Tabs property is bound to the TabControl's ItemsSource in the ApplicationView. 此Tabs属性绑定到ApplicationView中的TabControl的ItemsSource。

AllNationsViewModel/AllNationsView are used to display all the nations that have been entered by the user. AllNationsViewModel / AllNationsView用于显示用户输入的所有国家/地区。 It also allows the user to create new nations and select a particular nation for closer inspection. 它还允许用户创建新的国家并选择一个特定的国家进行更仔细的检查。 The AllStatesViewModel/AllStatesView do the same but for states. AllStatesViewModel / AllStatesView对状态执行相同操作。

Finally I have the NationViewModel/NationsView that deals with a particular nation; 最后,我有NationViewModel / NationsView处理特定国家; also here there are StateViewModel/StateView that do the same for a state. 此处还有StateViewModel / StateView对状态执行相同操作。

For a nation you can at the moment only input a name but for a state you can input a name as well as the nation it is part of. 对于一个国家,您现在只能输入一个名称,但对于一个州,您可以输入一个名称以及它所属的国家。 The nation is selected using a ComboBox where all the nations created in the nations tab show up. 使用ComboBox选择国家,其中所有国家选项卡中创建的国家都会显示出来。

I use a static class called DataFacade as an interface to my data store. 我使用一个名为DataFacade的静态类作为我的数据存储的接口。 It is possible to add, remove and retrieve a list of nations/states using this interface; 可以使用此界面添加,删除和检索国家/州的列表; also it triggers events when something is added or removed. 它还会在添加或删除某些内容时触发事件。

The problem I am having is that when there is a state selected in the AllStatesViewModel (CurrentStateViewModel property) and I go to the nations tab and then back to the states tab the currently selected state has lost its nation. 我遇到的问题是,当AllStatesViewModel(CurrentStateViewModel属性)中选择了一个状态,然后我转到NATIONAL选项卡,然后返回状态选项卡,当前选择的状态已失去其国家。 All the other states are still ok tough. 所有其他州仍然很难。

I will try to show the relevant code below (I have removed irrelevant code from some methods): 我将尝试显示下面的相关代码(我从一些方法中删除了不相关的代码):

State class: 州级:

class State
{
   public string Name { get; set; }

   public Nation Nation { get; set; }
}

TabControl in the ApplicationView: ApplicationView中的TabControl:

<TabControl ItemsSource="{Binding Tabs}" Margin="6">
   <TabControl.ItemTemplate>
      <DataTemplate>
         <ContentPresenter Content="{Binding DisplayName}" />
      </DataTemplate>
   </TabControl.ItemTemplate>
   <TabControl.ContentTemplate>
      <DataTemplate>
         <ContentPresenter Content="{Binding }" />
      </DataTemplate>
   </TabControl.ContentTemplate>
</TabControl>

When the user creates a nation the AddCommand of the AllNationsViewModel is triggered: 当用户创建国家时,将触发AllNationsViewModel的AddCommand:

private void Add(NationViewModel vm)
{
   DataFacade.AddNation(vm.Nation);
}

The AllStatesViewModel gets notified when a nation gets added to the data store: 当一个国家被添加到数据存储时,AllStatesViewModel会收到通知:

private void OnDataStoreNationsChanged(object sender, DataFacadeEventArgs e)
{
   Nations.Add(new NationViewModel(e.Context as Nation));
}

The Nations property above is an ObservableCollection of NationViewModels. 上面的Nations属性是NationViewModels的ObservableCollection。 Now, this property is used by the ComboBox in the StateView to populate its items so a nation can be selected when creating/editing a state: 现在,StateView中的ComboBox使用此属性来填充其项目,以便在创建/编辑状态时可以选择国家/地区:

<ComboBox Grid.Row="1" Grid.Column="1" SelectedValue="{Binding Nation}" SelectedValuePath="Nation" ItemsSource="{Binding DataContext.Nations, RelativeSource={RelativeSource AncestorType={x:Type local:AllStatesView}}}">
   <ComboBox.ItemTemplate>
      <DataTemplate>
         <TextBlock Text="{Binding Name}" />
      </DataTemplate>
   </ComboBox.ItemTemplate>
</ComboBox>

I believe the problem has to do with the binding above. 我认为这个问题与上面的绑定有关。 Because if I don't bind to the Nations property in AllStatesViewModel but instead bind to a temporary property in the ApplicationViewModel everything works. 因为如果我没有绑定到AllStatesViewModel中的Nations属性,而是绑定到ApplicationViewModel中的临时属性,一切正常。 Can it be that the AllStatesView is thrown away by the TabControl when I go to another tab therefor the binding above sets the Nation property of my StateViewModel to null? 当我转到另一个选项卡时,TabControl是否会抛弃AllStatesView,因为上面的绑定将我的StateViewModel的Nation属性设置为null? When I debug I see that I get a null when exiting the states tab. 当我调试时,我看到退出状态选项卡时我得到一个null。

How would someone who is not a beginner like me solve this situation? 像我这样的初学者怎么会解决这种情况呢? I find my temporary solution rather ugly. 我发现我的临时解决方案相当丑陋。 I am not entirely sure how I should handle the data store access since all the MVVM examples I have found don't focus on this part. 我不完全确定如何处理数据存储访问,因为我发现的所有MVVM示例都没有关注这一部分。

EDIT: Addded some pictures as requested: 编辑:按要求添加一些图片:

Atm I just have the simplest testing GUI set-up: Atm我只有最简单的测试GUI设置:

Here you see the AllNationsView, atm the NationView is only the "Name" TextBlock and the TextBox at the top. 在这里你看到AllNationsView,atm NationView只是“Name”TextBlock和顶部的TextBox。

国家

Here is the AllStatesView, at the top is the currently selected state (displayed using StateView). 这是AllStatesView,顶部是当前选择的状态(使用StateView显示)。 Where you now see that USA is selected as nation for Montana, if I go to the Nations tab and then back to the States tab the nation for Montana is now blank. 你现在看到美国被选为蒙大拿州的国家,如果我进入国家选项卡然后回到州选项卡,蒙大拿州的国家现在是空白的。 If I select Florida it still has USA as its nation. 如果我选择佛罗里达州,它仍然以美国为国家。

状态

WPF only keeps the UI for the active tab in memory. WPF仅将活动选项卡的UI保留在内存中。 When you change tabs that UI is destroyed and the UI of the new tab is created and rebound. 当您更改选项卡时,将销毁UI并创建新选项卡的UI并进行回弹。

There are a few ways around the problem you are having. 您可以通过几种方式解决问题。 You can use the Repository Pattern to store and access your data sources separate from the view models. 您可以使用存储库模式存储和访问与视图模型分开的数据源。 Basically, an outside object holds your data sources, such as the lists of states and nations. 基本上,外部对象保存您的数据源,例如州和国家列表。 That way they don't get destroyed when the active tab changes. 这样,当活动选项卡更改时,它们不会被销毁。

The other option is to store the data sources on your ApplicationViewModel and access them via a references to the ApplicationViewModel on each individual tab's view model. 另一个选项是将数据源存储在ApplicationViewModel ,并通过对每个单独选项卡视图模型上的ApplicationViewModel的引用来访问它们。 You shouldn't have to use a RelativeSource binding anywhere in that. 您不必在任何地方使用RelativeSource绑定。

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

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