简体   繁体   中英

WPF ComboBox selection change after switching tabs

I made a project based on nested tabs. the nested tabs are different instance of the same viemModel and the same UI. when I switch between the tabs he comboboxes present in the tabs chenge thei selection depending on the tab that is loosing focus.

I add both the viewmodels and the view of my test project. thank you in advance for your help

main window

<Window.Resources>

    <DataTemplate DataType="{x:Type local:IntermediateViewModel}">
        <local:IntermediateView />
    </DataTemplate>

    <DataTemplate x:Key="HeaderedTabItemTemplate">
        <Grid>
            <ContentPresenter
                        Content="{Binding Path=Header, UpdateSourceTrigger=PropertyChanged}" 
                        VerticalAlignment="Center" >
            </ContentPresenter>
        </Grid>
    </DataTemplate>

    <Style x:Key="SimpleTabItemStyle" TargetType="TabItem">
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border Name="Border" BorderThickness="1" BorderBrush="#555959">
                            <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center"
                                 ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True" Height ="40" MinWidth ="90"/>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="#555959" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <DataTemplate x:Key="DefaultTabControlTemplate">
        <TabControl IsSynchronizedWithCurrentItem="True" 
                        BorderThickness="0" 
                        ItemsSource="{Binding}" 
                        ItemTemplate="{StaticResource HeaderedTabItemTemplate}"
                        ItemContainerStyle="{StaticResource SimpleTabItemStyle}"
                        SelectionChanged="TabControl_SelectionChanged"
                        />
    </DataTemplate>


    <!---->


</Window.Resources>

<Grid MinHeight="200" MinWidth="300">
    <Grid.RowDefinitions>
        <RowDefinition Height="260*" />
        <RowDefinition Height="51*" />
    </Grid.RowDefinitions>
    <Border >
        <ContentControl 
            Content="{Binding Path=Workspaces}" 
            ContentTemplate="{DynamicResource DefaultTabControlTemplate}"
             />
    </Border>
    <Button Grid.Row="1" Content="Add" Command="{Binding AddCommand}"/>
</Grid>

view model (create a different istance each time)

class MainWindowViewModel : WorkspacesViewModel<IntermediateViewModel>
{
    public MainWindowViewModel()
    {
        this.WorkspacesView.CurrentChanged += new EventHandler(WorkspacesView_CurrentChanged);
    }

    void WorkspacesView_CurrentChanged(object sender, EventArgs e)
    {
    }

    RelayCommand myVar = null;
    public ICommand AddCommand
    {
        get 
        {
            return myVar ?? (myVar = new RelayCommand(param => 
            {
                SetWindow(new IntermediateViewModel("AA" + this.Workspaces.Count) );
            })); 
        }
    }

first level tab

    <UserControl.Resources>

    <DataTemplate DataType="{x:Type local:ClassViewModel}">
        <local:ClassView />
    </DataTemplate>
</UserControl.Resources>

<Border>
    <ContentControl Content="{Binding Path=CurrentWorkspace, Mode=OneWay}" Loaded="ContentControl_Loaded" DataContextChanged="ContentControl_DataContextChanged" IsVisibleChanged="ContentControl_IsVisibleChanged" LayoutUpdated="ContentControl_LayoutUpdated" TargetUpdated="ContentControl_TargetUpdated" Unloaded="ContentControl_Unloaded" />
</Border>

first level viewmodel

class IntermediateViewModel : WorkspacesViewModel { public string Header { get; set; }

    public IntermediateViewModel(string header)
    {
        Header = header;
        SetWindow(new ClassViewModel(header));
    }
}

nested tab

    <UserControl.Resources>
    <CollectionViewSource x:Key="StatusView" Source="{Binding Path=StatusList}"/>
</UserControl.Resources>
<Grid>
    <ComboBox Name="_spl2Status" ItemsSource="{Binding Source={StaticResource StatusView}}"
      SelectedValue="{Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
      SelectedValuePath="FL_TYPE"
      DisplayMemberPath="ID_TYPE" Margin="76,12,0,0" Height="40" VerticalAlignment="Top" HorizontalAlignment="Left" Width="146"
               DataContextChanged="_spl2Status_DataContextChanged"
               IsVisibleChanged="_spl2Status_IsVisibleChanged"
               Loaded="_spl2Status_Loaded"
                SelectionChanged="_spl2Status_SelectionChanged"
               >
    </ComboBox>
</Grid>

nested tab view model

public enum myTypes
{ 
    tipo0 = 0,
    tipo1 = 1,
    tipo2 = 2,
}

class ClassViewModel : WorkspaceViewModel
{
    public ClassViewModel(string name)
    {
        Name = name;
    }

    public string Name { get; set; }

    private List<IntEnumType> _statusList = null;
    public List<IntEnumType> StatusList
    {
        get
        {
            if (_statusList == null)
                _statusList = new List<IntEnumType>()
                {
                    new IntEnumType((int)myTypes.tipo0, myTypes.tipo0.ToString()),
                    new IntEnumType((int)myTypes.tipo1, myTypes.tipo1.ToString()),
                    new IntEnumType((int)myTypes.tipo2, myTypes.tipo2.ToString()),
                };
            return _statusList;
        }
    }

    private int myVar = 1;
    public int MyProperty
    {
        get 
        {
            return myVar; 
        }
        set 
        {
            if (myVar != value)
            {
                myVar = value;
                OnPropertyChanged(() => MyProperty);
            }
        }
    }
}

public class TabItemStyleSelector : StyleSelector
{
    public Style MainTabItem { get; set; }
    public Style ChildrenTabItem { get; set; }
    public Style SpecificationTabItem { get; set; }

    public override Style SelectStyle(object item, DependencyObject container)
    {
        //if (item is IHome)
        //    return MainTabItem;
        //else if (item is SpecificationItemViewModel)
        //    return SpecificationTabItem;
        //else
            return ChildrenTabItem;
    }
}

代码有点难以完全遵循,但我猜问题是你的ClassViewModel只有一个实例,它是存储组合框选择的地方{Binding Path=MyProperty ,所以无论存储什么在MyProperty将反映在组合框的所有实例中,无论它们位于何处。

Well this is a bit late, but as I'm facing the same issue, I want to share my analysis.

When you change your tabs, you change the DataContext of the current Tab to your other ViewModel and hence also the ItemsSource of your ComboBox.

In case your previously selected Item (SelectedItem) is not contained within the new ItemsSource, the ComboBox fires a SelectionChanged-Event and therefore sets the SelectedIndex to -1.

Altough this default behaviour of the ComboBox might make sense, it's very annoying in many cases.

We've derived an own class from ComboBox, handling that. But it's not very satisfying as you loose some default behaviour you most probably need.

The problem is in your loaded event handlers.

When you switch tabs your unloading one tab and loading a new one.

I suspect your changing MyComboBox.SelectedIndex in _spl2Status_Loaded .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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