【问题标题】:How to create an array of labels in wpf?如何在 wpf 中创建标签数组?
【发布时间】:2012-12-20 23:06:52
【问题描述】:

我正在尝试在我的 WPF 应用程序中模拟 LED 指示灯(大约 16 个)。我从串口获得 2 个字节,根据这些位,我需要打开/关闭应用程序窗口上的 LED 指示灯。 示例:0xFF、0xFE => 除了最后一个 LED 之外的所有 LED 都亮起。 我使用深色背景颜色的标签来表示关闭 LED,使用明亮背景颜色表示开启 LED。 如果我有一个标签数组,那么我可能会做这样的事情:

for(i = 0; i < 16; i++)
{
  if(bitArray[i] == true)
    lblLED[i].Background = Brushes.Pink;
  else
    lblLED[i].Background = Brushes.Maroon;
}

关于执行此操作的最佳方法有什么建议吗?可以显示这将如何工作的示例代码将很有帮助。谢谢!

【问题讨论】:

  • 你到底遇到了什么问题?
  • 最好的方法是创建一个ItemsControl 并使用ItemTemplate 以LED 指示灯样式显示每个项目。
  • 我不知道如何在 xaml 中创建标签数组,然后在 C# 中使用它来更改背景颜色和其他属性。

标签: c# wpf arrays labels


【解决方案1】:

我相信您可以弄清楚如何做您所要求的,但是让我们考虑一下手头的工具?你有一个布尔数组,看起来。正如建议的那样,ItemsControl 可以很好地处理它们。首先,让我们做一些代码隐藏来将我们的布尔值转换为画笔来设置我们项目的背景。

using System;
using System.Windows.Media;
using System.Windows.Data;
using System.Globalization;

namespace MyNamespace
{
    public class BoolToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // return a Pink SolidColorBrush if true, a Maroon if false
            return (bool)value ? Brushes.Pink : Brushes.Maroon;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
             return (SolidColorBrush)value == Brushes.Pink;
        }
    }
}

这将允许您在绑定到ItemsControl 时将您的bool[] bitArray 转换为一系列画笔。现在来一些 Xaml :

首先,确保在 xmlns 属性以及系统核心库(请参阅 xmlns 属性)中声明您的本地命名空间(其中包含我们刚刚定义的转换器)。

<Window x:Class="MyNamespace.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    <!-- our local namespace -->
    xmlns:my="clr-namespace:MyNamespace"
    <!-- system core library -->
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="600" Width="900">
    <Grid>
        <ItemsControl Name="LEDPanel"> <!-- Need to Name this Control in order to set the ItemsSource Property at startup -->
            <ItemsControl.Resources>
                <my:BoolToBrushConverter x:Key="LEDConverter" /> <!-- Here we define our converter for use, note the preceding my: namespace declaration -->
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" /> <!-- this will make the items defined in the ItemTemplate appear in a row -->
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type sys:Boolean}"> <-- We will be binding our ItemsControl to a bool[] so each Item will be bound to a bool -->
                    <Border Margin="3" CornerRadius="10" Height="20" Width="20" BorderThickness="2" BorderBrush="Silver" Background="{Binding Converter={StaticResource LEDConverter}}" />
                    <!-- This is where we describe our item. I'm drawing a round silver border and then binding the Background to the item's DataContext (implicit) and converting the value using our defined BoolToBrushConverter -->
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

编辑:我忘记了数据绑定。在窗口的构造函数中:

public MainWindow()
{
    InitializeComponent();
    LEDPanel.ItemsSource = bitArray;
}

【讨论】:

  • 谢谢你,解释得很好,我希望我也可以将你的答案标记为答案,但我最终使用了第二种解决方案,它非常适合我的需要
【解决方案2】:

涵盖的概念是 INotifyPropertyChanges(在 .net 4.5 中(其他版本的更改最小,但概念相同))、ItemsControl 和最后的样式触发器。

INotifyPropertyChanges

我的第一步是将 INotifyPropertyChanges 放在我们的主窗口上,以自动通知 WPF 控件任何更改。您将您的位数组转换为列表,并在需要时简单地将其放入(也许在计时器上?)。请注意,无论有多少...控件都会扩展。

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private List<bool> _LedStates;

    public List<bool> LedStates
    {
        get { return _LedStates; }
        set
        {
            _LedStates = value;
            NotifyPropertyChanged();

        }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        LedStates = new List<bool>() {true, false, true};
    }


    #region INotifyPropertyChanged
    /// <summary>
    /// Event raised when a property changes.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises the PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected virtual void NotifyPropertyChanged( [CallerMemberName] String propertyName = "" )
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler( this, new PropertyChangedEventArgs( propertyName ) );
        }
    } 
    #endregion

}

ItemsControl 和样式触发器

然后在 WPF xaml 中,我们将绑定到布尔列表并使用项目模板(为找到的每个数据项考虑一个通用迷你视图)。在该模板中,我们将根据布尔值的状态显示红色或绿色。

不需要转换器,因为我们设置了一个与目标值相协调的样式触发器。如果 Textblocks 文本为“True”,我们将显示绿色,当“False”时,我们将触发/显示红色。

<Window x:Class="WPFBindToArray.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">
    <Grid>

<ItemsControl x:Name="icBitViewer"
                ItemsSource="{Binding LedStates}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel HorizontalAlignment="Stretch"
                        IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" Grid.Column="0">
                <TextBlock.Style>
                    <Style TargetType="{x:Type TextBlock}">
                        <Style.Triggers>
                            <Trigger Property="Text" Value="True">
                                <Setter Property="Background" Value="Green" />
                            </Trigger>
                            <Trigger Property="Text"  Value="False">
                                <Setter Property="Background" Value="Red" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBlock.Style>
            </TextBlock>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

    </Grid>
</Window>

这个程序在这里运行的结果是:

【讨论】:

  • 谢谢,这有帮助...触发器实现就可以了!
【解决方案3】:

试试这个。这显然只是一个示例,我建议您使用 WPF 的功能,并且可能使用与 Label 不同的控件。

Func<ushort, bool[]> getBits = s =>
{
    var bools = new bool[sizeof (ushort)*8];
    for (var i = 0; i < bools.Length; i++)
        bools[i] = (s & 1 << i) > 0;
    return bools;
};
var bits = getBits(2);
var labels = new Label[sizeof (ushort)*8];
for (var i = 0; i < labels.Length; i++)
{
    var label = new Label {Background = bits[i] ? Brushes.Green : Brushes.Red};
    labels[i] = label;
}
//Do something with the Label array

【讨论】:

  • 改用itemscontrol,更简单
  • 我只是尽量保持与作者的情况一样接近,因为他似乎有标签和位的数组。
  • 我的观点总是问为什么,大多数人问这些问题是因为他们不知道更好的方法。我赞成代码,但我不鼓励这种方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
  • 1970-01-01
  • 2019-07-10
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多