这是我的情况。到目前为止,我知道我可以创建资源字典来定义自定义样式,如选项卡控件。我想在主窗口中使用那些样式。问题是在哪里定义事件,例如按钮单击样式中的按钮?说我想做Visibility="Binding {Button A's click}"
?
<Window x:Class="test_tabControl3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel LastChildFill="True">
<Grid DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Zoom:"
VerticalAlignment="Center"
Margin="5"/>
<!-- Allows to zoom the TabControl (see the ScaleTransform defined on the TC) -->
<Slider x:Name="uiScaleSlider"
Grid.Column="1"
ToolTip="Drag the slider to change the zoom-level ..."
SmallChange="0.1"
LargeChange="1"
Minimum="1"
Maximum="10"
Value="2"
Margin="5"/>
</Grid>
<Grid x:Name="Layer1" Visibility="Binding {Button A's click}">
<TabControl x:Name="tc" Margin="5" SelectedIndex="0" Style="{StaticResource FirstTab}" Visibility="Visible">
<TabControl.LayoutTransform>
<!-- Allows to zoom the control's content using the slider -->
<ScaleTransform CenterX="0"
CenterY="0"
ScaleX="{Binding ElementName=uiScaleSlider,Path=Value}"
ScaleY="{Binding ElementName=uiScaleSlider,Path=Value}"/>
</TabControl.LayoutTransform>
<TabItem Header="Tab 1" Style="{StaticResource FirstTabItem}">
<Canvas Background="AliceBlue"/>
</TabItem>
<TabItem Header="Tab 2" Style="{StaticResource FirstTabItem}">
<Canvas Background="Lavender"/>
</TabItem>
<TabItem Header="Tab 3" IsEnabled="False" Style="{StaticResource FirstTabItem}"
ToolTip="I'm disabled.">
<Canvas Background="PaleGreen"/>
</TabItem>
</TabControl>
</Grid>
</DockPanel>
</Window>
更新 TabControl在资源字典中定义
<Style TargetType="{x:Type TabControl}" x:Key="FirstTab">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Background="AliceBlue"
Padding="{StaticResource TabItemPanel_Padding}">
<!-- This is the area in which TabItems (the strips) will be drawn. -->
<TabPanel IsItemsHost="True"/>
</Border>
<Button Grid.Column="1">A</Button>
</Grid>
<Border BorderThickness="1,0,1,1"
....
UPDATE2
关于样式模板的更多问题。
我知道我需要定义ContentPresenter ContentSource
来在模板中呈现属性。
下面我有两个样式首先用于TabControl,第二个用于Tabitem。
在TabItem样式中,我有ContentSource="Header"
,其中Header
是tabItem的属性,而在TabControl样式ContentSource="SelectedContent"
中。所以我想知道为什么不能ContentSource="Content"
Content
下tabItem控件中定义的tabItem属性。
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
....
<ContentPresenter ContentSource="SelectedContent" Margin="0"/>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}" >
<Setter Property="Header"
Value="{Binding Header}" />
<Setter Property="Content"
Value="{Binding Content}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Grid Height="35" VerticalAlignment="Bottom">
<Border Name="Border"
Background="{StaticResource TabItem_BackgroundBrush_Unselected}"
BorderBrush="{StaticResource TabItem_BorderBrush_Selected}"
Margin="{StaticResource TabItemMargin_Base}"
BorderThickness="2,1,1,0"
CornerRadius="3,3,0,0"
>
<Grid>
<Grid.ColumnDefinitions>
<!-- Text / TabItem's Caption -->
<ColumnDefinition/>
<!-- Close button -->
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="7,2,12,2"
RecognizesAccessKey="True">
</ContentPresenter>
答案 0 :(得分:1)
这是一个如何使用命令的完整示例,此示例也演示了如何使用视图模型来填充选项卡控件。
这将为您提供构建基于mvvm的应用程序的开始
XAML
<Grid xmlns:l="clr-namespace:CSharpWPF">
<Grid.DataContext>
<l:ViewModel />
</Grid.DataContext>
<TabControl ItemsSource="{Binding TabItems}"
SelectedItem="{Binding CurrentItem}"
x:Name="tabControl">
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Header"
Value="{Binding Header}" />
<Setter Property="Content"
Value="{Binding Content}" />
</Style>
</TabControl.Resources>
</TabControl>
<Button Content="X"
IsEnabled="{Binding HasItems,ElementName=tabControl}"
Command="{Binding CloseTab}"
CommandParameter="{Binding SelectedItem,ElementName=tabControl}"
HorizontalAlignment="Right"
VerticalAlignment="Top" />
</Grid>
我保持示例小,但您可以应用任何您想要的样式,您只需要找到合适的绑定路径。
码
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
namespace CSharpWPF
{
class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
TabItems = new ObservableCollection<TabData>();
//dummy data
TabItems.Add(new TabData() { Header = "Tab 1", Content = "Tab content 1" });
TabItems.Add(new TabData() { Header = "Tab 2", Content = "Tab content 2" });
TabItems.Add(new TabData() { Header = "Tab 3", Content = "Tab content 3" });
TabItems.Add(new TabData() { Header = "Tab 4", Content = "Tab content 4" });
TabItems.Add(new TabData() { Header = "Tab 5", Content = "Tab content 5" });
CurrentItem = TabItems[3];
CloseTab = new SimpleCommand(OnCloseTab);
}
public ObservableCollection<TabData> TabItems { get; private set; }
private TabData _currentItem;
public TabData CurrentItem
{
get { return _currentItem; }
set { _currentItem = value; }
}
public ICommand CloseTab { get; private set; }
private void OnCloseTab(object obj)
{
TabData tab = obj as TabData;
if (tab != null && TabItems.Contains(tab))
{
TabItems.Remove(tab);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
class TabData
{
public string Header { get; set; }
public object Content { get; set; }
}
class SimpleCommand : ICommand
{
Action<object> action;
public SimpleCommand(Action<object> action)
{
this.action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
action(parameter);
}
}
}
尝试新的测试项目并分享您的反馈
修改强>
看完你发送的样本后,我必须说你做得很好。你几乎就在那里,你只是错过了一件微不足道的事情按钮上的命令在示例代码中工作,因为按钮的DataContext与命令所在的位置相同,但是当您将按钮放在选项卡本身时,数据上下文将更改为TabData,没有那个命令
所以你需要找到tabitem的父标签控件上的相应datacontext,你可以使用RelativeSource和FindAncestor找到适当的控件并绑定到DataContext的CloseTab属性,这是你想要的命令
例如
Command="{Binding DataContext.CloseTab,RelativeSource={RelativeSource FindAncestor,AncestorType=TabControl}}"
还要弄清楚这种问题密切关注“输出”窗口,我在调试代码时发现了这个问题
System.Windows.Data错误:40:BindingExpression路径错误:&#39; CloseTab&#39;在&#39; object&#39;上找不到的属性&#39;&#39; TabData&#39; (的HashCode = 37561097)&#39 ;. BindingExpression:路径= CloseTab;的DataItem =&#39; TabData&#39; (的HashCode = 37561097);目标元素是&#39;按钮&#39; (名称=&#39;&#39);目标财产是&#39; Command&#39; (键入&#39; ICommand&#39;)
这告诉我绑定正在尝试解析TabData类
实例上的CloseTab属性对于你的第二个问题,你可以简单地参考WPF: Multiple content presenters in a custom control?它有一个明确的答案