【问题标题】:easily accessible array of controls易于访问的控件阵列
【发布时间】:2023-03-08 19:08:01
【问题描述】:

我对整个 XAML 很陌生。

我需要创建一个具有常量行数和列数(例如 2x5)的表格(网格),并在每个单元格中放置一个 TextBlock

我怎样才能正确地做到这一点,以便我可以轻松地更改单元格的数据?

例如,我想创建一个接受 1 个整数作为偏移量的函数:

void fillDate(int offset)

并从偏移量开始填充单元格。

即使用 `fillData(3)' 为 2x5 调用函数将生成下表:

 | | |1|2
3|4|5|6|7 

【问题讨论】:

    标签: c# wpf xaml microsoft-metro


    【解决方案1】:

    试试看这个。在这里,您使用 ListBox 作为项目数组的容器,并使用 UniformGrid 作为占位符(您可以将行数和列数绑定到类的属性以在运行时更改它们)

    <Window x:Class=MyWindowClass ... >
        ... 
    <ListBox 
     ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=MyWindowClass}, Path=myItems}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="{Binding Path=ColumnsInArray}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=MyField}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    
    </Window>
    

    在代码中你只需要改变你的集合元素

    class MyWindowClass: INotifyPropertyChanged
    {
        public MyWindowClass():base()
        {
             ...
             InitializeComponent();
             myItems = new ObservableCollection<MyObject>();
             myItems.Add(new MyObject);// First Element
             myItems.Add(new MyObject);// Second Element
             ...
             myItems.Add(new MyObject);// Last Element
             ...
        }
    
        int columns=5;
        public int ColumnsInArray
        {
            get{return columns;} 
            set {columns=value; NotifyPropertyChanged("ColumnsInArray");}
        }
    
        public ObservableCollection<MyObject> myItems
        {
            get{ ... }
            set{ ... }
        }
    

    设置项目

        void setItem(int index,MyObject newObject)
        {
            ...
            myItems[index]=newObject;
            ...
        }
    
        void setItem(int x, int y, MyObject newObject)
        {
            ...
            int index = y*columns+x;
            setItem(index,newObject);
            ...
        }
    

    INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        void NotifyPropertyChanged( string prop )
        {
            if( PropertyChanged != null ) 
            PropertyChanged( this , new PropertyChangedEventArgs( prop ) );
        }
    
    }
    
    public class MyObject
    {
        public string MyField{get;set;}
    }
    

    【讨论】:

    • 主要思想是将 ObservableCollection(相当于一维数组)映射到一个二维数组,该数组设置一行中的元素数。这里 Xcoord = index % Columns; Ycoord = 索引/列;
    【解决方案2】:

    这没什么特别的,来自 Silverlight/XAML 背景,但可能或多或少会起作用。您可能需要针对细微的 API 差异(在没有 VS 的记事本中编写)和未经测试的细微差异进行调整,但应该为您提供入门所需的内容。

    private void fillDate(int offset)
    {
        int rows = 2;
        int columns = 5;
        int currentEntry = 1;
    
        for(int rowIndex = 0; rowIndex < rows; rowIndex++)
        {
            for (int columnIndex = 0; columnIndex < columns; columnIndex++)
            {
                if (currentEntry > offset)
                {
                    TextBlock textEntry = new TextBlock();
                    textEntry.Text = currentEntry.ToString();
                    Grid.SetRow(textEntry, rowIndex);
                    Grid.SetColumn(textEntry, columnIndex);
                }
                currentEntry++;
            }
        }
    }
    

    编辑:刚刚意识到您可能想要一个在“空”单元格中没有文本的 TextBlock,在这种情况下,将内部循环的代码替换为:

    TextBlock textEntry = new TextBlock();
    Grid.SetRow(textEntry, rowIndex);
    Grid.SetColumn(textEntry, columnIndex);
    if (currentEntry > offset)
        textEntry.Text = currentEntry.ToString();
    currentEntry++;
    

    编辑:根据您的评论,在创建控件时首先运行一个方法来构建网格并填充所有文本字段并将它们存储在某种列表中:

    private int Rows = 2;
    private int Columns = 5;
    private TextBlock[][] TextEntries;
    
    private void CreateTextBlocks()
    {
        TextEntries = new TextBlock[Rows][];
        for (int rowIndex = 0; rowIndex < rows; rowIndex++)
        {
            entries[rowIndex] = new string[columns];
            for (int columnIndex = 0; columnIndex < columns; columnIndex++)
            {
                TextBlock textEntry = new TextBlock();
                Grid.SetRow(textEntry, rowIndex);
                Grid.SetColumn(textEntry, columnIndex);
                myGrid.Children.Add(textEntry);
    
                TextEntries[rowIndex][columnIndex] = textEntry;
            }
        }
    }
    

    随后运行另一种方法来根据需要更改值:

    private void fillDate(int offset)
    {
        int currentEntry = 1;
    
        for(int rowIndex = 0; rowIndex < Rows; rowIndex++)
        {
            for (int columnIndex = 0; columnIndex < Columns; columnIndex++)
            {
                TextBlock textEntry = TextEntries[rowIndex][columnIndex]
    
                if (currentEntry > offset)
                    textEntry.Text = currentEntry.ToString();
                else
                    textEntry.Text = String.Empty;
    
                currentEntry++;
            }
        }
    }
    

    【讨论】:

    • 您的代码的问题(至少我认为您的代码有问题!:D)是我无法访问 created TextBlock秒后。即在函数的第二次调用中。
    • 啊,是的。我忘了将它添加到网格(myGrid.Children.Add(textEntry))。如果您想重用现有的文本块,要么将它们存储在一个数组中,要么通过网格的Children 属性访问它们。
    • @MBZ 我添加了另一个实现,看看它是否有帮助。
    猜你喜欢
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 2013-06-14
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多