Using XAML binding how can I visually alert users that a tab contains data (in child controls)?
My WPF TabControl contains multiple TabItems. I want to visually alert users that data exists on a tab. Currently users have to click each tab to be sure nothing important was overlooked. Each tab represents a step (with instructions) of a multi-step workflow. Each workflow contains a random combination of steps (some steps may be skipp开发者_开发百科ed). I'd like tabs to change color or otherwise make it clear that one or more of it's child controls contain instructions.
What binding syntax could I add to either the parent TabControl or the child controls (typically TextBoxes) to achieve this goal? I'd like to minimize repetitive code and use a generic Style or DataTrigger that could be added to the resources section of the Window or App. A challenge is that the control with data may live in a second TabControl within the parent tab so there is not always a direct parent/child relationship.
I sense that my user interface could be redesigned and improved. I'd welcome suggestions along with your answer to my question.
Thanks in advance.
I think you could use a data template or style template to achieve this. Unfortunately my WPF and XAML is rusty so I can't offer code. But templates are were you want to look.
Whoops should have finished reading the post.
So you want to preload the data? Assuming you are using some MVVM framework you could have your controller load the data and send a message to the form that contains and renders the tab.
I would change the ControlTemplate
of TabItem
and use DataTriggers
from view model boolean to trigger border
colors.
Edit: A very minimal example, uses the same flag for all tabs, doesn't turn off when the user selects it, but you will get the idea. The key is the MultiDataTrigger
in the template.
<Window x:Class="TabControl.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">
<Window.Resources>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Margin="0,0,-4,0"
Background="{StaticResource LightBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource WindowBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding HasNewData}" Value="True"/>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="Red" />
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Header 1"/>
<TabItem Header="Header 2"/>
<TabItem Header="Header 3"/>
<TabItem Header="Header 4"/>
</TabControl>
</Grid>
</Window>
Code behind:
public partial class MainWindow : Window
{
public bool HasNewData { get; set; }
public MainWindow()
{
InitializeComponent();
this.HasNewData = true;
this.DataContext = this;
}
}
I alert users a tab has NO data by modifying the TabItem Header (that's the text on top). If no data exists I set the Foreground color to Gray so it appears disabled but is still clickable allowing data to be added. In addition I append the word "Blank" to the text. Ultimately tabs with no data have a grayed out header which reads "Tab 1 Blank", "Tab 2 Blank" etc.
Details:
I use two binding statements (for the Header and Foreground):
<TabItem x:Name="StepOneTabItem"
Header="{Binding StepOneDataExistsText}"
Foreground="{Binding Path=StepOneDataExistsText,
Converter={StaticResource tabForegroundGrayWhenBlankConverter}}">
Both Bindings make use of the property StepOneDataExistsText which I created on my DataContext. That property is simply a string set conditionally. When bound to the Header it displays either "Tab 1" or "Tab 1 Blank". The same property bound to Foreground uses a Converter to return either a Gray or Black SolidColorBrush (Gray when "Blank" is at the end of StepOneDataExistsText).
[ValueConversion(typeof(string), typeof(System.Windows.Media.SolidColorBrush))]
public class TabForegroundGrayWhenBlankConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string passedInTextValue = (string)value;
if (passedInTextValue.ToUpper().Contains("BLANK"))
{
return new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Gray);
}
else
{
return new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
Initially I attempted to change the Background color of the TabItem but ran into difficulties as described here.
精彩评论