如何在 TabControl ItemsSource 更新后 select 第一个 TabItem?
How to select first TabItem after TabControl ItemsSource update?
我的应用程序使用 TabItems 来显示不同的用户控件,例如 login/products/settings 页面。当您打开应用程序时,只有一个选项卡可用并且 selected,即登录页面,成功登录后,该页面将被删除,其他页面将加载第一个 selected。当我注销时,所有页面都被删除并再次加载登录页面,但没有 selected。我正在使用 MVVM 模式,所以不想在 ViewModel 中写 UI 中的操作。
如果 ItemTab 是列表中的唯一一个,是否可以 select ItemTab?例如,在代码隐藏中编写一个方法并将其连接到 TabControl SelectedIndex?
我尝试在代码隐藏中为 SourceUpdated 和 TargetUpdated 创建事件处理程序,但没有成功。
MainWindow.xaml
<TabControl x:Name="ApplicationTabs"
ItemsSource="{Binding Tabs}"
SelectedIndex="0">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<DataTemplate DataType="{x:Type VMod:LoginViewModel}">
<Pages:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:AdminViewModel}">
<Pages:AdminView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:ProductsViewModel}">
<Pages:ProductsView />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type inter:ITab}">
<TextBlock>
<Run Text="{Binding TabName}" />
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate> </TabControl>
MainWindowViewModel.cs(BaseViewModel 有 INotifyPropertyChanged)
class MainWindowViewModel : BaseViewModel
{
public static IList<ITab> Tabs { get; set; }
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
public MainWindowViewModel()
{
Tabs = new ObservableCollection<ITab>();
LoadLoginPage();
}
public static void RaiseStaticPropertyChanged (string PropertyName)
{StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(PropertyName));}
public static void LoadLoginPage()
{
if (Tabs != null) Tabs.Clear();
Tabs.Add(new LoginViewModel());
RaiseStaticPropertyChanged("Tabs");
} // LoadTabs() create and load login page to the tab collection
public static void LoadTabs()
{
if (Tabs != null) Tabs.Clear();
Tabs.Add(new AdminViewModel());
Tabs.Add(new ProductsViewModel());
RaiseStaticPropertyChanged("Tabs");
} // LoadTabs() method loads specific tabs to the collection
public static void LogIn(object x)
{
LoggedInUser = (User)x;
LoadTabs();
}
public static void LogOut(object x)
{
LoggedInUser = null;
LoadLoginPage();
}
}
经过多次尝试和错误,我最终发现我最初关于代码隐藏中的 TargetUpdated 事件处理程序的想法是正确的。我只是不知道我的 ItemSource 绑定需要 NotifyOnTargetUpdated。多亏了我没有违反 MVVM 规则。
更正后的绑定:
<TabControl x:Name="ApplicationTabs"
ItemsSource="{Binding Tabs,
NotifyOnTargetUpdated=True}"
Grid.Row="1"
TargetUpdated="TabsUpdated"> (...) </TabControl>
后面的代码:
private void TabsUpdated(object sender, DataTransferEventArgs e)
{
if(ApplicationTabs.Items.Count == 1)
{
ApplicationTabs.SelectedIndex = 0;
}
}
我的应用程序使用 TabItems 来显示不同的用户控件,例如 login/products/settings 页面。当您打开应用程序时,只有一个选项卡可用并且 selected,即登录页面,成功登录后,该页面将被删除,其他页面将加载第一个 selected。当我注销时,所有页面都被删除并再次加载登录页面,但没有 selected。我正在使用 MVVM 模式,所以不想在 ViewModel 中写 UI 中的操作。
如果 ItemTab 是列表中的唯一一个,是否可以 select ItemTab?例如,在代码隐藏中编写一个方法并将其连接到 TabControl SelectedIndex?
我尝试在代码隐藏中为 SourceUpdated 和 TargetUpdated 创建事件处理程序,但没有成功。
MainWindow.xaml
<TabControl x:Name="ApplicationTabs"
ItemsSource="{Binding Tabs}"
SelectedIndex="0">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<DataTemplate DataType="{x:Type VMod:LoginViewModel}">
<Pages:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:AdminViewModel}">
<Pages:AdminView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:ProductsViewModel}">
<Pages:ProductsView />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type inter:ITab}">
<TextBlock>
<Run Text="{Binding TabName}" />
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate> </TabControl>
MainWindowViewModel.cs(BaseViewModel 有 INotifyPropertyChanged)
class MainWindowViewModel : BaseViewModel
{
public static IList<ITab> Tabs { get; set; }
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
public MainWindowViewModel()
{
Tabs = new ObservableCollection<ITab>();
LoadLoginPage();
}
public static void RaiseStaticPropertyChanged (string PropertyName)
{StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(PropertyName));}
public static void LoadLoginPage()
{
if (Tabs != null) Tabs.Clear();
Tabs.Add(new LoginViewModel());
RaiseStaticPropertyChanged("Tabs");
} // LoadTabs() create and load login page to the tab collection
public static void LoadTabs()
{
if (Tabs != null) Tabs.Clear();
Tabs.Add(new AdminViewModel());
Tabs.Add(new ProductsViewModel());
RaiseStaticPropertyChanged("Tabs");
} // LoadTabs() method loads specific tabs to the collection
public static void LogIn(object x)
{
LoggedInUser = (User)x;
LoadTabs();
}
public static void LogOut(object x)
{
LoggedInUser = null;
LoadLoginPage();
}
}
经过多次尝试和错误,我最终发现我最初关于代码隐藏中的 TargetUpdated 事件处理程序的想法是正确的。我只是不知道我的 ItemSource 绑定需要 NotifyOnTargetUpdated。多亏了我没有违反 MVVM 规则。
更正后的绑定:
<TabControl x:Name="ApplicationTabs"
ItemsSource="{Binding Tabs,
NotifyOnTargetUpdated=True}"
Grid.Row="1"
TargetUpdated="TabsUpdated"> (...) </TabControl>
后面的代码:
private void TabsUpdated(object sender, DataTransferEventArgs e)
{
if(ApplicationTabs.Items.Count == 1)
{
ApplicationTabs.SelectedIndex = 0;
}
}