简体   繁体   中英

WPF: Change Tab Header Font Color When Button is Pressed

I am working on a program that has multiple tabs, each tab containing multiple buttons that when clicked execute a SQL call in a BackgroundWorker object. Once a button has been clicked the other buttons are disabled as long as the SQL process is working

Because some of these SQL calls can take upwards of an hour I am using the BackgroundWorker so that the GUI still responds to user input (ie, changing tabs) but the buttons are disabled until the current SQL process has completed.

One of the feature requests is to change the color of the currently selected tab's header font to green (normally black) to indicate that one of the buttons from this tab is the one that started the currently running SQL. Once the SQL is complete the font color should return to black.

Is it possible to do this with a style/datatrigger? I cannot think of a way to apply a style to the currently selected tab once the button is pressed and then maintain that coloring if I switch tabs while the background worker is still working.

My other thought on this would be a method that changes the tab header font color via code whenever I click a button and then change it back once the background worker has completed but this would require updating all the ButtonClicked() methods.

I am open to any other solutions as well.

I know about the async/await feature but cannot change the code that executes the SQL using BackgroundWorker, so please no suggestions to use async/await.

The ViewModel instance that is bound to the tab could be having a property called running.

public bool IsRunning { get; set; }

bind the background color to the background Property with a Converter. http://wpftutorial.net/ValueConverters.html

depending on true/false the converter will return a color. You could even pass the color as an argument in the binding. Before executing the query to set it to true, and once done set it to true.

myVM.IsRunning=true;
executeQuery();
myVM.IsRunning=false;

Something like this should be what you want:

<TabControl ItemsSource="{Binding Tabs}">

    <TabControl.ItemTemplate>
        <DataTemplate>

            <TextBlock Text="{Binding TabHeader}">
                <TextBlock.Style>
                    <Style TargetType="TextBlock">

                        <Setter Property="Foreground" Value="Black"/>

                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsWorking}" Value="True">

                                <Setter Property="Foreground" Value="Green"/>

                            </DataTrigger>
                        </Style.Triggers>

                    </Style>
                </TextBlock.Style>
            </TextBlock>

        </DataTemplate>
    </TabControl.ItemTemplate>

</TabControl>

Where the view model of each item in the Tabs collection would look something like:

public class TabViewModel
{
    public string TabHeader { get; set; }
    public bool IsWorking { get; set; }
}

Obviously, the view model should implement notify property changed.

Try with

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Background="LightGray" 
    Title="Window1" Height="350" Width="700" >
    <Window.Resources>
        <Style x:Key="myHeaderStyle" TargetType="{x:Type TextBlock}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TabItem}}, Path=DataContext}" Value="True">
                    <Setter Property="Foreground" Value="Green" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate x:Key="myHeader">
            <TextBlock Text="{Binding}" Style="{DynamicResource myHeaderStyle}" />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TabControl>
            <TabItem x:Name="FirstTab" Header="First tab" HeaderTemplate="{DynamicResource myHeader}" DataContext="{Binding FirstTabSelected}">
                <Button Click="Button_Click">
                    First button
                </Button>
            </TabItem>
            <TabItem Header="Second tab" HeaderTemplate="{DynamicResource myHeader}"  DataContext="{Binding SecondTabSelected}">
                <Button Click="Button_Click_1">
                    Second button
                </Button>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

And code behind

[ImplementPropertyChanged]
public partial class MainWindow : Window
{
    public bool FirstTabSelected { get; set; }
    public bool SecondTabSelected { get; set; }

    public MainWindow()
    {
        FirstTabSelected = true;
        SecondTabSelected = true;
        InitializeComponent();

        this.DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        FirstTabSelected = !FirstTabSelected;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        SecondTabSelected = !SecondTabSelected;
    }
}

I'm using Fody propertyChanged so I don't need to implement INotifyPropertyChanged manually.

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