XAML/MVVM 帮助实施屏幕网格
XAML/MVVM help for implementing screen grid
作为 XAML/MVVM 的完全初学者,我想请求一些帮助来实现 24x14 字母屏幕。
XAML 的实现非常简单,我认为
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
然而,我正在努力解决的是数据绑定。
我想写一些类似“UpdateScreen()”方法的东西,用数据填充那个网格,其中
- 每个网格单元有 1 个字母
- 每个字母都有一种颜色(红色、绿色...)
- 每个字母有大有小
我当前的 ViewModel 看起来像这样(在 Microsoft.Toolkit.Mvvm 的帮助下):
public partial class ScreenViewModel : ObservableObject
{
[ObservableProperty]
private ScreenText[] _screen;
//ScreenText consists of char value, Color color, bool isBig
[ICommand]
private void ButtonPressed(AppButton button)
{
System.Diagnostics.Debug.WriteLine($"Button {button} was pressed");
}
private void UpdateScreen()
{
[.?.]
}
}
它应该与应用程序的实际逻辑进行通信,生成一个 ScreenText[],然后传递回 ViewModel。
我如何将它连接到 ScreenGrid?
感谢您的帮助。
这是一种以编程方式将单元格添加为网格子级的方法,每个单元格都绑定到视图模型中列表的一个元素。
鉴于:
public class ScreenText
{
// I think binding to xaml requires string, not char.
public string Value {
get => value.ToString();
}
...
}
和ScreenViewModel.cs:
public class ScreenViewModel : ObservableObject
{
// List or ObservableCollection (not Array) usually used for Xamarin Forms.
public ObservableCollection<ScreenText> Texts { get; } = new ObservableCollection<ScreenText>();
...
}
MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ManipulateGridChildren.MainPage">
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
</ContentPage>
MainPage.xaml.cs:
using System.Collections.Generic;
using Xamarin.Forms;
namespace ManipulateGridChildren
{
public partial class MainPage : ContentPage
{
const int NRows = 14;
static int NColumns = 24;
public MainPage(ScreenViewModel vm)
{
InitializeComponent();
// So you can access from any method.
VM = vm;
AddCells(vm);
BindingContext = vm;
}
private ScreenViewModel VM;
// Used a dictionary, so can add cells in any order.
private Dictionary<int, Label> cells = new Dictionary<int, Label>();
private void AddCells(ScreenViewModel vm)
{
// Grid rows and columns are numbered from "0".
for (int row = 0; row < NRows; row++) {
for (int column = 0; column < NColumns; column++) {
var cell = AddCell(row, column, vm);
}
}
}
private Label AddCell(int row, int column, ScreenViewModel vm)
{
var index = CellKey(row, column);
var cell = new Label();
// NOTE: I think "Value" has to be a "string" not a "char".
cell.SetBinding(TextProperty, $"Texts[{index}].Value");
cell.TextColor = Color.Black;
cell.BackgroundColor = Color.White;
cell.HorizontalTextAlignment = TextAlignment.Center;
cell.VerticalTextAlignment = TextAlignment.Center;
ScreenGrid.Children.Add(cell, column, row);
// This dictionary makes it easier to access individual cells later.
cells[index] = cell;
return cell;
}
// Assign unique key to each cell.
private int CellKey(int row, int column)
{
return row * NColumns + column;
}
// Can use this to access an individual cell later.
// For example, you might change some property on that cell.
private Label GetCell(int row, int column)
{
return cell[CellKey(row, column)];
}
}
备选方案:
对于不使用视图模型的任何人,请参阅 。
我的解决方案(最小示例)如下所示:
在 XAML 中,网格定义如下
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
ViewModel 看起来像这样(在 Toolkit.Mvvm 的帮助下):
public partial class ScreenViewModel : ObservableObject
{
const int LINES = 14;
public ObservableCollection<ScreenText> Screen { get; } = new ObservableCollection<ScreenText>();
public ScreenViewModel()
{
for (int i = 0; i < LINES; i++)
{
Screen.Add(new ScreenText());
}
}
[ICommand]
private void ButtonPressed(AppButton button)
{
System.Diagnostics.Debug.WriteLine($"Button {button} was pressed");
//Do some business logic and manipulate the screen
OnPropertyChanged(nameof(Screen));
}
}
最后 MainPage.Xaml.cs:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
//Setup Screen
AddScreenCells();
}
private void AddScreenCells()
{
for (int row = 0; row < ScreenGrid.RowDefinitions.Count; row++)
{
for (int col = 0; col < ScreenGrid.ColumnDefinitions.Count; col++)
{
Label label = new Label();
label.SetBinding(Label.TextProperty, $"{nameof(ScreenViewModel.Screen)}[{row}].{nameof(ScreenText.Letters)}[{col}]");
ScreenGrid.Add(label, col, row);
}
}
}
}
作为 XAML/MVVM 的完全初学者,我想请求一些帮助来实现 24x14 字母屏幕。
XAML 的实现非常简单,我认为
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
然而,我正在努力解决的是数据绑定。
我想写一些类似“UpdateScreen()”方法的东西,用数据填充那个网格,其中
- 每个网格单元有 1 个字母
- 每个字母都有一种颜色(红色、绿色...)
- 每个字母有大有小
我当前的 ViewModel 看起来像这样(在 Microsoft.Toolkit.Mvvm 的帮助下):
public partial class ScreenViewModel : ObservableObject
{
[ObservableProperty]
private ScreenText[] _screen;
//ScreenText consists of char value, Color color, bool isBig
[ICommand]
private void ButtonPressed(AppButton button)
{
System.Diagnostics.Debug.WriteLine($"Button {button} was pressed");
}
private void UpdateScreen()
{
[.?.]
}
}
它应该与应用程序的实际逻辑进行通信,生成一个 ScreenText[],然后传递回 ViewModel。
我如何将它连接到 ScreenGrid?
感谢您的帮助。
这是一种以编程方式将单元格添加为网格子级的方法,每个单元格都绑定到视图模型中列表的一个元素。
鉴于:
public class ScreenText
{
// I think binding to xaml requires string, not char.
public string Value {
get => value.ToString();
}
...
}
和ScreenViewModel.cs:
public class ScreenViewModel : ObservableObject
{
// List or ObservableCollection (not Array) usually used for Xamarin Forms.
public ObservableCollection<ScreenText> Texts { get; } = new ObservableCollection<ScreenText>();
...
}
MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ManipulateGridChildren.MainPage">
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
</ContentPage>
MainPage.xaml.cs:
using System.Collections.Generic;
using Xamarin.Forms;
namespace ManipulateGridChildren
{
public partial class MainPage : ContentPage
{
const int NRows = 14;
static int NColumns = 24;
public MainPage(ScreenViewModel vm)
{
InitializeComponent();
// So you can access from any method.
VM = vm;
AddCells(vm);
BindingContext = vm;
}
private ScreenViewModel VM;
// Used a dictionary, so can add cells in any order.
private Dictionary<int, Label> cells = new Dictionary<int, Label>();
private void AddCells(ScreenViewModel vm)
{
// Grid rows and columns are numbered from "0".
for (int row = 0; row < NRows; row++) {
for (int column = 0; column < NColumns; column++) {
var cell = AddCell(row, column, vm);
}
}
}
private Label AddCell(int row, int column, ScreenViewModel vm)
{
var index = CellKey(row, column);
var cell = new Label();
// NOTE: I think "Value" has to be a "string" not a "char".
cell.SetBinding(TextProperty, $"Texts[{index}].Value");
cell.TextColor = Color.Black;
cell.BackgroundColor = Color.White;
cell.HorizontalTextAlignment = TextAlignment.Center;
cell.VerticalTextAlignment = TextAlignment.Center;
ScreenGrid.Children.Add(cell, column, row);
// This dictionary makes it easier to access individual cells later.
cells[index] = cell;
return cell;
}
// Assign unique key to each cell.
private int CellKey(int row, int column)
{
return row * NColumns + column;
}
// Can use this to access an individual cell later.
// For example, you might change some property on that cell.
private Label GetCell(int row, int column)
{
return cell[CellKey(row, column)];
}
}
备选方案:
对于不使用视图模型的任何人,请参阅
我的解决方案(最小示例)如下所示:
在 XAML 中,网格定义如下
<Grid x:Name="ScreenGrid"
RowDefinitions="*, *, *, *, *, *, *, *, *, *, *, *, *, *"
ColumnDefinitions="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*"/>
ViewModel 看起来像这样(在 Toolkit.Mvvm 的帮助下):
public partial class ScreenViewModel : ObservableObject
{
const int LINES = 14;
public ObservableCollection<ScreenText> Screen { get; } = new ObservableCollection<ScreenText>();
public ScreenViewModel()
{
for (int i = 0; i < LINES; i++)
{
Screen.Add(new ScreenText());
}
}
[ICommand]
private void ButtonPressed(AppButton button)
{
System.Diagnostics.Debug.WriteLine($"Button {button} was pressed");
//Do some business logic and manipulate the screen
OnPropertyChanged(nameof(Screen));
}
}
最后 MainPage.Xaml.cs:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
//Setup Screen
AddScreenCells();
}
private void AddScreenCells()
{
for (int row = 0; row < ScreenGrid.RowDefinitions.Count; row++)
{
for (int col = 0; col < ScreenGrid.ColumnDefinitions.Count; col++)
{
Label label = new Label();
label.SetBinding(Label.TextProperty, $"{nameof(ScreenViewModel.Screen)}[{row}].{nameof(ScreenText.Letters)}[{col}]");
ScreenGrid.Add(label, col, row);
}
}
}
}