如何将 textblock.foreground 绑定到变量?(WPF C#)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24494720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:02:37  来源:igfitidea点击:

How to bind textblock.foreground to a variable? (WPF C#)

c#wpfvisual-studio-2013textblock

提问by Stunna

So I am hoping to alter my program such that I can run a function to check and see if the foreground color should be black or silver. I am hoping to gray out fields that are not "accessible".

所以我希望改变我的程序,这样我就可以运行一个函数来检查前景色是否应该是黑色或银色。我希望将“不可访问”的字段变灰。

My form currently looks like: enter image description here

我的表格目前看起来像: 在此处输入图片说明

I was hoping to "gray out" the "No maintenance required" fields. But I am having problems with trying to define a binding element to the font foreground in my data template.

我希望将“无需维护”字段“变灰”。但是我在尝试为数据模板中的字体前景定义绑定元素时遇到问题。

I've tried everything from trying to define an IValueConverter class within the main window code behind, to defining a window key resource, but it doesn't appear that I can do that within a data template on the textblock element itself?

我已经尝试了从尝试在主窗口代码中定义 IValueConverter 类到定义窗口键资源的所有方法,但似乎我无法在文本块元素本身的数据模板中执行此操作?

Any suggestions/help would be appreciated. Thanks!

任何建议/帮助将不胜感激。谢谢!

XAML:

XAML:

<Grid Margin="0,0,2,0">

    <ListBox x:Name="allSites_LB" 
             HorizontalAlignment="Left" 
             Height="400" 
             Margin="20,60,0,0" 
             VerticalAlignment="Top" 
             Width="945"
             Loaded="allSites_LB_Loaded" 
             BorderThickness="1" SelectionChanged="allSites_LB_SelectionChanged"
             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
             >
        <ListBox.ItemTemplate >
            <DataTemplate >
                <Border BorderBrush="Black" BorderThickness="0,0,0,1" Margin="-20,1,0,1" Padding="0,5,0,5" >
                    <Grid Margin="75,3" >
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="200" />
                            <ColumnDefinition Width="400" />
                            <ColumnDefinition Width="345" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding SiteNo}" Grid.Column="0" FontSize="16" />
                        <TextBlock Text="{Binding Address}" Grid.Column="1" FontSize="16" Margin="50,1" />
                        <TextBlock Text="{Binding MaintStatus}" Grid.Column="2" FontSize="16" />
                    </Grid>
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <Button x:Name="viewHistory_BTN" 
            Content="View History" 
            HorizontalAlignment="Left" 
            Height="52" 
            Margin="20,496,0,0" 
            VerticalAlignment="Top" 
            Width="172" FontSize="20"
            />

    <Button x:Name="startMaintenance_BTN" 
            Content="Start Maintenance"
            HorizontalAlignment="Left" 
            Height="52" 
            Margin="793,496,0,0" 
            VerticalAlignment="Top" 
            Width="172" FontSize="20"
            />
    <TextBox x:Name="Site_Address" 
             HorizontalAlignment="Left" 
             Height="21" 
             Margin="51,39,0,0" 
             TextWrapping="Wrap" 
             Text="Site Number" 
             VerticalAlignment="Top" 
             Width="75" 
             BorderBrush="White" 
             IsReadOnly="True" 
             IsEnabled="False"

             />
    <TextBox x:Name="Address_Title" 
             HorizontalAlignment="Left" 
             Height="21" 
             Margin="380,34,0,0" 
             TextWrapping="Wrap" 
             Text="Address" 
             VerticalAlignment="Top" 
             Width="75" 
             BorderBrush="White"
             IsReadOnly="True" 
             IsEnabled="False"

             />
    <TextBox x:Name="maint_Title" 
             HorizontalAlignment="Left" 
             Height="21" 
             Margin="699,34,0,0" 
             TextWrapping="Wrap" 
             Text="Maintenance Record" 
             VerticalAlignment="Top" 
             Width="117" 
             BorderBrush="White" 
             IsReadOnly="True" 
             IsEnabled="False"
             />

</Grid>

C# Code Behind:

背后的 C# 代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SqlClient;



namespace SiteMaintenance
{

public partial class MainWindow : Window
{

    /**
     * CLASS VARIABLES
     * */
    private SqlConnection localdbConnection;        // Connection to Site Maintenance DB (LOCAL)
    private System.Data.DataSet allSitesResults;



    // MAIN THREAD
    public MainWindow()
    {
        InitializeComponent();

        // try to open SQL Connection
        try {
            localdbConnection = new SqlConnection(Properties.Settings.Default.localdb);
            localdbConnection.Open();
        } catch(Exception ex) {
           System.Windows.MessageBox.Show("local SQL connection unable to connect");
           return;
        }

        viewHistory_BTN.IsEnabled = false;
        startMaintenance_BTN.IsEnabled = false;
        startMaintenance_BTN.IsDefault = true;
    }

    /**
     * Load dataset into datagrid 
     * LAZY LOADING
     * */
    private void DataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        // init command object
        SqlCommand myCommand = new SqlCommand();
        myCommand.CommandText = "dbo.usp_GetSites";
        myCommand.CommandType = System.Data.CommandType.StoredProcedure;
        myCommand.Connection = localdbConnection;

        // init data adaptor
        SqlDataAdapter sites = new SqlDataAdapter();
        sites.SelectCommand = myCommand;

        //init DataSet
        allSitesResults = new System.Data.DataSet();

        sites.Fill(allSitesResults, "tblSites");

        int tableCount = allSitesResults.Tables.Count;

        System.Data.DataTable test = allSitesResults.Tables[0];

        int rowCount = test.Rows.Count;





    }

    private void sites_DG_CurrentCellChanged(object sender, EventArgs e)
    {
        String siteName = allSitesResults.Tables[0].Rows[0][1].ToString();

    }

    private void allSites_LB_Loaded(object sender, RoutedEventArgs e)
    {
        // init command object
        SqlCommand myCommand = new SqlCommand();
        myCommand.CommandText = "dbo.usp_GetSitesANDCompletedDate";
        myCommand.CommandType = System.Data.CommandType.StoredProcedure;
        myCommand.Connection = localdbConnection;

        // init data adaptor
        SqlDataAdapter sites = new SqlDataAdapter();
        sites.SelectCommand = myCommand;

        //init DataSet
        allSitesResults = new System.Data.DataSet();

        sites.Fill(allSitesResults, "tblSites");

        allSites_LB.ItemsSource = allSitesResults.Tables["tblSites"].DefaultView;

    }


    // do not allow selection of maintenance records that do not exist
    private void allSites_LB_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

        // grab the index
        int selectedIndex = allSites_LB.SelectedIndex;
        if (selectedIndex == -1) return;                //WITHOUT THIS CHECK, UN-SELECTION WILL CAUSE LOGIC FAILURE

        System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];

        // grab the completed date field
        String completedDate = tempData["CompletedDate"].ToString();
        String siteMaintID = tempData["SiteMaintID"].ToString();

        // remove selected index if completed date and site Maint ID is null
        if (siteMaintID != "" && completedDate == "")
        {
            startMaintenance_BTN.IsEnabled = true;
        }
        else 
        {
            allSites_LB.SelectedIndex = -1;
            startMaintenance_BTN.IsEnabled = false;
        }

    }


    private String maintRequired(object sender, SelectionChangedEventArgs e)
    {
        int selectedIndex = allSites_LB.SelectedIndex;
        if (selectedIndex < 0) return null;

        System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];

        // grab the completed date field
        String completedDate = tempData["CompletedDate"].ToString();
        String siteMaintID = tempData["SiteMaintID"].ToString();

        if (siteMaintID != "" && completedDate == "")
        {
            return "Maintenance Required";
        }
        else
        {
            return "No Maintenance";
        }
    }

}

}

}

回答by BTownTKD

There are generally two good approaches for you to choose from, when binding the Foreground color to a piece of data. Depending on who you ask, different people will have different preferences. So... here's both!

在将前景色绑定到一段数据时,通常有两种很好的方法供您选择。根据你问的是谁,不同的人会有不同的偏好。所以……两者都有!

First Method: Style with Triggers

第一种方法:带触发器的样式

This method basically identifies 'special' behavior when a certain set of conditions are met. In this case, we're changing the foreground color to Gray, when the status == "No Maintenance Required"

当满足一组特定条件时,此方法基本上可以识别“特殊”行为。在这种情况下,当状态 ==“无需维护”时,我们将前景色更改为灰色

<Style TargetType="TextBlock">
    <Setter Property="Foreground" Value="Black" /> <!-- default value -->
    <Style.Triggers>
        <DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}" Value="No Maintenance Required">
            <Setter Property="Foreground" Value="Gray" /> <!-- special behavior -->
        </DataTrigger>
    </Style.Triggers>
</Style>

In this case, just assign your TextBlock the appropriate Styleproperty.

在这种情况下,只需为您的 TextBlock 分配适当的Style属性。

Second Method: Use an IValueConverter

第二种方法:使用 IValueConverter

This approach creates a custom "IValueConverter implementation, which converts your Text value to a Color. From there, we bind directly to our text value, and ensure that the converter always provides the proper color.

这种方法创建了一个自定义的“IValueConverter 实现,它将您的文本值转换为颜色。从那里,我们直接绑定到我们的文本值,并确保转换器始终提供正确的颜色。

public class MaintenaceColorConverter : IValueConverter
{

    public Color NormalColor { get; set; }
    public Color NoMaintenanceRequiredColor { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value.ToString() == "No Maintenance Required")
            return NoMaintenanceRequiredColor;

        return NormalColor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

In your XAML:

在您的 XAML 中:

<Window.Resources>
    <local:MaintenaceColorConverter x:Key="myColorConverter" NormalColor="Black" NoMaintenanceRequiredColor="Gray" />
</Window.Resources>

In your TextBlock:

在您的文本块中:

<TextBlock Text="{Binding MaintStatus}" Foreground="{Binding MaintStatus, Converter={StaticResource myColorConverter}}" />

Improvements

改进

With either of these approaches, it would be better to have a MaintenanceStatusboolean or enum value, and bind your styling conditions to that. It's a bad idea to use string-comparisons. That's just begging for trouble. These examples used string comparison because... well... that's all that was available from your provided example code.

使用这两种方法中的任何一种,最好有一个MaintenanceStatus布尔值或枚举值,并将您的样式条件绑定到该值。使用字符串比较是个坏主意。那只是自找麻烦。这些示例使用字符串比较,因为......好吧......这就是您提供的示例代码中可用的全部内容。

回答by paparazzo

More than you asked for but this is from some existing code

比你要求的多,但这是来自一些现有的代码

<Style TargetType="ListViewItem">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=IsMaintenance}" Value="True">
            <Setter Property="Background" Value="Gainsboro"  />
            <Setter Property="Foreground" Value="Red" />
        </DataTrigger>
        <Trigger Property="IsSelected" Value="True" >
            <Setter Property="FontWeight" Value="Bold" />
        </Trigger>
    </Style.Triggers>
</Style>

回答by Stunna

Thanks for the feedback! I went with BTownTKD's suggestion on implementing an IValueConverter although with some alterations in my code. I discovered I needed to define "local" scope in my window properties in XAML.

感谢您的反馈!尽管在我的代码中做了一些改动,但我还是接受了 BtownTKD 关于实现 IValueConverter 的建议。我发现我需要在 XAML 的窗口属性中定义“本地”范围。

Also, I was discovering that the binding wasn't actually changing the text color. After stepping through the code and seeing that the method was being properly invoked, I then hardcoded the results returned into the XAML to make sure they were working (foreground="black" or foreground="#FF00000"). I noticed when stepping through the code that the return object was a "color" object in the original binding, and by me hard-coding the colors into the XAML, they were actually strings. So I altered the code slightly to add in a .ToString() to the object I was returning and VOILA it worked! Thanks again for the help!

此外,我发现绑定实际上并没有改变文本颜色。在逐步执行代码并看到该方法被正确调用后,我将返回的结果硬编码到 XAML 中以确保它们正常工作(foreground="black" 或 foreground="#FF00000")。我注意到在逐步执行代码时,返回对象是原始绑定中的“颜色”对象,通过我将颜色硬编码到 XAML 中,它们实际上是字符串。所以我稍微修改了代码,将 .ToString() 添加到我返回的对象中,瞧它工作了!再次感谢您的帮助!

FYI here's the updated code bits:

仅供参考,这里是更新的代码位:

XAML:

   <Window x:Class="SiteMaintenance.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SiteMaintenance"
        Title="MainWindow" 
        Height="600" 
        Width="1000">
    <Window.Resources>
        <local:MaintenenceColorConverter x:Key="MyColorConverter" NormalColor="Black" NoMaintenanceRequiredColor="Gray" />
    </Window.Resources>

    <Grid Margin="0,0,2,0">

        <ListBox x:Name="allSites_LB" 
                 HorizontalAlignment="Left" 
                 Height="400" 
                 Margin="20,60,0,0" 
                 VerticalAlignment="Top" 
                 Width="945"
                 Loaded="allSites_LB_Loaded" 
                 BorderThickness="1" SelectionChanged="allSites_LB_SelectionChanged"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                 >
            <ListBox.ItemTemplate >
                <DataTemplate >
                    <Border BorderBrush="Black" BorderThickness="0,0,0,1" Margin="-20,1,0,1" Padding="0,5,0,5" >
                        <Grid Margin="75,3" >
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="200" />
                                <ColumnDefinition Width="400" />
                                <ColumnDefinition Width="345" />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding SiteNo}" Grid.Column="0" FontSize="16" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}"  />
                            <TextBlock Text="{Binding Address}" Grid.Column="1" FontSize="16" Margin="50,1" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}"  />
                            <TextBlock Text="{Binding MaintStatus}" Grid.Column="2" FontSize="16" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}" />
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <Button x:Name="viewHistory_BTN" 
                Content="View History" 
                HorizontalAlignment="Left" 
                Height="52" 
                Margin="20,496,0,0" 
                VerticalAlignment="Top" 
                Width="172" FontSize="20"
                />

        <Button x:Name="startMaintenance_BTN" 
                Content="Start Maintenance"
                HorizontalAlignment="Left" 
                Height="52" 
                Margin="793,496,0,0" 
                VerticalAlignment="Top" 
                Width="172" FontSize="20"
                />
        <TextBox x:Name="Site_Address" 
                 HorizontalAlignment="Left" 
                 Height="21" 
                 Margin="51,39,0,0" 
                 TextWrapping="Wrap" 
                 Text="Site Number" 
                 VerticalAlignment="Top" 
                 Width="75" 
                 BorderBrush="White" 
                 IsReadOnly="True" 
                 IsEnabled="False"

                 />
        <TextBox x:Name="Address_Title" 
                 HorizontalAlignment="Left" 
                 Height="21" 
                 Margin="380,34,0,0" 
                 TextWrapping="Wrap" 
                 Text="Address" 
                 VerticalAlignment="Top" 
                 Width="75" 
                 BorderBrush="White"
                 IsReadOnly="True" 
                 IsEnabled="False"

                 />
        <TextBox x:Name="maint_Title" 
                 HorizontalAlignment="Left" 
                 Height="21" 
                 Margin="699,34,0,0" 
                 TextWrapping="Wrap" 
                 Text="Maintenance Record" 
                 VerticalAlignment="Top" 
                 Width="117" 
                 BorderBrush="White" 
                 IsReadOnly="True" 
                 IsEnabled="False"
                 />

    </Grid>
</Window>

C# Code Behind:

背后的 C# 代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SqlClient;



namespace SiteMaintenance
{

public partial class MainWindow : Window
{

    /**
     * CLASS VARIABLES
     * */
    private SqlConnection localdbConnection;        // Connection to Site Maintenance DB (LOCAL)
    private System.Data.DataSet allSitesResults;



    // MAIN THREAD
    public MainWindow()
    {
        InitializeComponent();

        // try to open SQL Connection
        try {
            localdbConnection = new SqlConnection(Properties.Settings.Default.localdb);
            localdbConnection.Open();
        } catch(Exception ex) {
           System.Windows.MessageBox.Show("local SQL connection unable to connect");
           return;
        }

        viewHistory_BTN.IsEnabled = false;
        startMaintenance_BTN.IsEnabled = false;
        startMaintenance_BTN.IsDefault = true;
    }

    /**
     * Load dataset into datagrid 
     * LAZY LOADING
     * */
    private void DataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        // init command object
        SqlCommand myCommand = new SqlCommand();
        myCommand.CommandText = "dbo.usp_GetSites";
        myCommand.CommandType = System.Data.CommandType.StoredProcedure;
        myCommand.Connection = localdbConnection;

        // init data adaptor
        SqlDataAdapter sites = new SqlDataAdapter();
        sites.SelectCommand = myCommand;

        //init DataSet
        allSitesResults = new System.Data.DataSet();

        sites.Fill(allSitesResults, "tblSites");

        int tableCount = allSitesResults.Tables.Count;

        System.Data.DataTable test = allSitesResults.Tables[0];

        int rowCount = test.Rows.Count;

    }


    private void sites_DG_CurrentCellChanged(object sender, EventArgs e)
    {
        String siteName = allSitesResults.Tables[0].Rows[0][1].ToString();

    }

    private void allSites_LB_Loaded(object sender, RoutedEventArgs e)
    {
        // init command object
        SqlCommand myCommand = new SqlCommand();
        myCommand.CommandText = "dbo.usp_GetSitesANDCompletedDate";
        myCommand.CommandType = System.Data.CommandType.StoredProcedure;
        myCommand.Connection = localdbConnection;

        // init data adaptor
        SqlDataAdapter sites = new SqlDataAdapter();
        sites.SelectCommand = myCommand;

        //init DataSet
        allSitesResults = new System.Data.DataSet();

        sites.Fill(allSitesResults, "tblSites");

        allSites_LB.ItemsSource = allSitesResults.Tables["tblSites"].DefaultView;

    }


    // do not allow selection of maintenance records that do not exist
    private void allSites_LB_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

        // grab the index
        int selectedIndex = allSites_LB.SelectedIndex;
        if (selectedIndex == -1) return;                //WITHOUT THIS CHECK, UN-SELECTION WILL CAUSE LOGIC FAILURE

        System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];

        // grab the completed date field
        String completedDate = tempData["CompletedDate"].ToString();
        String siteMaintID = tempData["SiteMaintID"].ToString();

        // remove selected index if completed date and site Maint ID is null
        if (siteMaintID != "" && completedDate == "")
        {
            startMaintenance_BTN.IsEnabled = true;
        }
        else 
        {
            allSites_LB.SelectedIndex = -1;
            startMaintenance_BTN.IsEnabled = false;
        }

    }


    private String maintRequired(object sender, SelectionChangedEventArgs e)
    {
        int selectedIndex = allSites_LB.SelectedIndex;
        if (selectedIndex < 0) return null;

        System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];

        // grab the completed date field
        String completedDate = tempData["CompletedDate"].ToString();
        String siteMaintID = tempData["SiteMaintID"].ToString();

        if (siteMaintID != "" && completedDate == "")
        {
            return "Maintenance Required";
        }
        else
        {
            return "No Maintenance";
        }
    }

}

public class MaintenenceColorConverter : IValueConverter
{

    public Color NormalColor { get; set; }
    public Color NoMaintenanceRequiredColor { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        if (value.ToString() == "No Maintenance Required") return NoMaintenanceRequiredColor.ToString();

        return NormalColor.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

}

}

}

I'll be cleaning up my code later with BTown's optimization, but at least its working!

稍后我将使用 Btown 的优化来清理我的代码,但至少它可以工作!