本文使用4个例子介绍TabControl的使用。包括xaml以及C#代码生成TabControl.其中第4个例子是使用TabControl来实现IO监控,作为工控软件的一部分。
【例1】使用TabControl以及 TabItem实现简单功能:
注意:TabControl的属性 TabStripPlacement可以对选项卡索引放置位置进行设置(上下左右)
<TabControl Margin="5" TabStripPlacement="Right">
<TabItem Header="Tab One">
<StackPanel Margin="5" >
<TextBlock>这是Tab 1</TextBlock>
<CheckBox>选项1</CheckBox>
<CheckBox>选项2</CheckBox>
<CheckBox>选项3</CheckBox>
</StackPanel>
</TabItem>
<TabItem Header="Tab two">
<StackPanel >
<TextBlock>这是Tab 2</TextBlock>
</StackPanel>
</TabItem>
</TabControl>
【例2】代码生成
选项卡1中:通过建立一个StackPanel(其中添加文本以及按钮);然后设置为TabItem1的Content。
public Window3()
{
InitializeComponent();
TabItem newTab1 = new TabItem();
newTab1.Header = "新选项卡1";
StackPanel stackpanel = new StackPanel() ;
stackpanel.Orientation = Orientation.Vertical;
stackpanel.Children.Add(new TextBlock { Text = "动态添加的页面1内容" });
stackpanel.Children.Add(new System.Windows.Controls.Button { Content = "按钮" });
newTab1.Content = stackpanel;
this.MyTab.Items.Add(newTab1);
TabItem newTab2 = new TabItem();
newTab2.Header = "新选项卡2";
newTab2.Content = new TextBlock { Text = "动态添加的页面2内容" };
this.MyTab.Items.Add(newTab2);
// 选择最后一个选项卡
MyTab.SelectedIndex = MyTab.Items.Count - 1;
this.DataContext = new MainViewModel3();
}
【例3】使用MVVM进行绑定
<Window x:Class="WpfApp1.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="Window3" Height="450" Width="800">
<TabControl Margin="5" TabStripPlacement="Top" Name="MyTab"
ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTab}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
public class TabItemModel
{
public string Header { get; set; }
public string Content { get; set; }
}
public class MainViewModel3
{
public ObservableCollection<TabItemModel> Tabs { get; } = new ObservableCollection<TabItemModel>();
public TabItemModel SelectedTab { get; set; }
public MainViewModel3()
{
Tabs.Add(new TabItemModel { Header = "第一页", Content = "内容1" });
Tabs.Add(new TabItemModel { Header = "第二页", Content = "内容2" });
SelectedTab = Tabs[1];
}
}
【例4】PLC的IO监控界面
本文使用Uni
<UserControl x:Class="WpfApp1.windowIO"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Background="#fafafa"
>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 模式切换 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<RadioButton x:Name="rbInputs" Content="全输入" GroupName="Mode" Margin="5" IsChecked="True" Checked="rbInputs_Checked" />
<RadioButton x:Name="rbOutputs" Content="全输出" GroupName="Mode" Margin="5" Checked="rbOutputs_Checked"/>
</StackPanel>
<!-- 分页内容 -->
<TabControl Grid.Row="1" x:Name="PagesTab" Background="Transparent" BorderThickness="0">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Visibility" Value="Collapsed"/>
<!-- 隐藏Tab头 -->
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
<!-- 翻页导航 -->
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="上一页" Click="PrevPage_Click" Style="{StaticResource MaterialDesignFlatButton}"/>
<TextBlock Text="{Binding CurrentPage}" Margin="10,0" VerticalAlignment="Center"/>
<Button Content="下一页" Click="NextPage_Click" Style="{StaticResource MaterialDesignFlatButton}"/>
</StackPanel>
</Grid>
</UserControl>
public partial class windowIO : UserControl
{
private windowIOModel _viewModel = new windowIOModel();
private int _itemsPerPage = 32; //
private int totalPages = 0;
public bool bInitialized = false;
public windowIO()
{
InitializeComponent();
this.DataContext = _viewModel;
UpdatePageContent();
bInitialized = true;
}
private void UpdatePageContent()
{
PagesTab.Items.Clear();
if (this.rbOutputs.IsChecked==true)
{
totalPages = (_viewModel.Outputs.Count + _itemsPerPage - 1) / _itemsPerPage;
}
else
{
totalPages = (_viewModel.Inputs.Count + _itemsPerPage - 1) / _itemsPerPage;
}
for (int page = 0; page < totalPages; page++)
{
var pageContent = new TabItem();
var grid = new UniformGrid() { Columns = 2, Margin = new Thickness(10) };
var UniformGrid_left = new UniformGrid() { Columns = 1 };
var UniformGrid_right = new UniformGrid() { Columns = 1 };
int i = 0;
if (rbInputs.IsChecked == true)
{
// 全输入模式
foreach (var input in _viewModel.Inputs.Skip(page * 32).Take(32))
{
if(i<16)
{
UniformGrid_left.Children.Add(new SingleIOMonitor
{
DataContext = input
//IsActive = input.IsActive
});
}
else
{
UniformGrid_right.Children.Add(new SingleIOMonitor
{
DataContext = input
//IsActive = input.IsActive
});
};
i++;
}
}
else
{
// 全输入模式
foreach (var output in _viewModel.Outputs.Skip(page * 32).Take(32))
{
if (i < 16)
{
UniformGrid_left.Children.Add(new SingleIOMonitor
{
DataContext = output
});
}
else
{
UniformGrid_right.Children.Add(new SingleIOMonitor
{
DataContext = output
});
}
i++;
}
}
grid.Children.Add(UniformGrid_left);
grid.Children.Add(UniformGrid_right);
pageContent.Content = grid;
PagesTab.Items.Add(pageContent);
}
PagesTab.SelectedIndex = _viewModel.CurrentPage=0;
}
private void PrevPage_Click(object sender, RoutedEventArgs e)
{
if (_viewModel.CurrentPage > 0)
{
_viewModel.CurrentPage--;
PagesTab.SelectedIndex = _viewModel.CurrentPage;
}
}
private void NextPage_Click(object sender, RoutedEventArgs e)
{
if (_viewModel.CurrentPage < totalPages)
{
_viewModel.CurrentPage++;
PagesTab.SelectedIndex = _viewModel.CurrentPage;
}
}
private void rbInputs_Checked(object sender, RoutedEventArgs e)
{
if(bInitialized==true)
{
UpdatePageContent();
}
}
private void rbOutputs_Checked(object sender, RoutedEventArgs e)
{
if (bInitialized == true)
{
UpdatePageContent();
}
}
}
/// <summary>
/// IO 标签类
/// </summary>
public class IOLabel : ObservableObject, IComparable<IOLabel>
{
public int index; //在byte数组中的序号
public string Address { get; set; } //地址
public string Comment { get; set; } //注释
/// <summary>
/// Value数值,即IO
/// </summary>
private bool _Value;
public bool Value
{
get => _Value;
set {
SetProperty(ref _Value, value);
}
}
public int CompareTo(IOLabel other)
{
if (other == null) return 1; // null视为最小
return index.CompareTo(other.index); // 使用int的CompareTo方法
}
}
public class windowIOModel : ObservableObject
{
public ObservableCollection<IOLabel> Inputs { get; } = new ObservableCollection<IOLabel>();
public ObservableCollection<IOLabel> Outputs { get; } = new ObservableCollection<IOLabel>();
public BytesArrayTag inputTags;
public BytesArrayTag OutputTags;
private int _currentPage;
public int CurrentPage
{
get => _currentPage;
set { SetProperty(ref _currentPage, value); }
}
}