C# 在c Wforms中具有可选项的二维网格?
如何实现10x10个可选元素的2D,每个元素都带有windows窗体中的文本? 有没有一个简单的方法可以做到这一点 我需要以一种有序的方式选择一些元素,在网格中建立索引,以便向我的机器人发送新位置。我的意思是:1:当被选中时,转到网格中标记为1的第一个选定元素 第二:选择时转到网格中标记为2的第二个选定元素。。。等等 网格将如下所示: 资料来源:C# 在c Wforms中具有可选项的二维网格?,c#,windows,winforms,gridview,C#,Windows,Winforms,Gridview,如何实现10x10个可选元素的2D,每个元素都带有windows窗体中的文本? 有没有一个简单的方法可以做到这一点 我需要以一种有序的方式选择一些元素,在网格中建立索引,以便向我的机器人发送新位置。我的意思是:1:当被选中时,转到网格中标记为1的第一个选定元素 第二:选择时转到网格中标记为2的第二个选定元素。。。等等 网格将如下所示: 资料来源: 我试图避免将100个复选框彼此靠近…将此作为答案发布,因为OP要求它: <Window x:Class="MiscSamples.GridRob
我试图避免将100个复选框彼此靠近…将此作为答案发布,因为OP要求它:
<Window x:Class="MiscSamples.GridRobot"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridRobot" Height="500" Width="600">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<TextBlock Text="Size:" Margin="2" DockPanel.Dock="Left"/>
<TextBox Text="{Binding Size}" IsReadOnly="True" DockPanel.Dock="Left" Margin="2" Width="50"/>
<Slider Maximum="20" Minimum="2" Value="{Binding Size}"/>
</DockPanel>
<StackPanel DockPanel.Dock="Left" Width="100" Margin="2">
<TextBlock Text="Route:" TextAlignment="Center" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding Route}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:D2},{1:D2}">
<Binding Path="Row"/>
<Binding Path="Column"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<Grid>
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding Size}" Columns="{Binding Size}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1">
<Button Command="{Binding DataContext.GoToCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate>
<Border Background="#05FFFFFF">
<Viewbox>
<TextBlock Text="{Binding PathIndex}"
TextAlignment="Center" VerticalAlignment="Center"/>
</Viewbox>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Canvas>
<!-- I was about to add the Robot Peg here and animate it -->
</Canvas>
</Grid>
</DockPanel>
</Window>
视图模型:
public class GridRobotViewModel: PropertyChangedBase
{
private int _size;
public int Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
CreateItems();
}
}
private ObservableCollection<GridItem> _squares;
public ObservableCollection<GridItem> Squares
{
get { return _squares ?? (_squares = new ObservableCollection<GridItem>()); }
}
private ObservableCollection<GridItem> _route;
public ObservableCollection<GridItem> Route
{
get { return _route ?? (_route = new ObservableCollection<GridItem>()); }
}
private void CreateItems()
{
Squares.Clear();
Route.Clear();
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
Squares.Add(new GridItem() {Row = i, Column = j});
}
}
}
private Command<GridItem> _goToCommand;
public Command<GridItem> GoToCommand
{
get { return _goToCommand ?? (_goToCommand = new Command<GridItem>(Goto){IsEnabled = true}); }
}
private void Goto(GridItem item)
{
if (item.PathIndex == null)
{
item.PathIndex = Squares.Max(x => x.PathIndex ?? 0) + 1;
Route.Add(item);
}
}
}
MVVM的支持类:
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
结果:
只需将我的代码复制粘贴到文件->新建项目->WPF应用程序中,然后自己查看结果。
你说的是10 x 10,但我更进一步,添加了一个滑块,使网格大小可自定义。
单击任何单元格将使其作为路由的一部分排队。
完全独立于分辨率。
我正要开始在上面放一些非常好的东西,动画,用椭圆表示的机器人运动,路径线,等等。
忘了winforms吧,它没用。
我可以推荐WPF吗?它确实更具可扩展性、可定制性和简单美观。实际上,您可以通过一个列表框在WPF中实现这一点。我想现在不是从Wforms更改为WPF的时候。。。我想这将是一个巨大的变化。这是一个PC程序的一部分,该程序支持与我们的机器人的用户界面。这个机器人是我在电子工程年级的项目。。。我们正在考虑在程序中添加此功能,如果这不超过1周。。。我们应该在几个月内交付最终文档…@leouru我已经有了它的运行版本。。。我正要开始做动画部分,如果你愿意,我可以发布代码。那太好了@HighCore!谢谢机器人实际上是如何移动的?从a点到B点是直线吗?加速/减速怎么样?真的很漂亮。这正是我所想的。。。有了路线信息,我可以在机器人中设置跟随它的功能。。。作为一名EE学生,我学习WPF需要多少钱?如果我过去知道WPF,我会选择它。。。此外,未找到ObservableCollection、INotifyPropertyChanged、PropertyChangedEventHandler和PropertyChangedEventArgs。。。我错过了什么?你没有重奏吗?Ctrl+Enter自动完成引用,需要使用System.ComponentModel,使用System.Collections.Generic。否则Ctrl+。在视觉研究中,我不。。。杰出的我还缺少使用System.Collections.ObjectModel;。。。难道不能为windows窗体执行此操作吗?请理解,我必须完成我的成绩项目。。。我想现在改变整个计划会很疯狂。。。也许如果不是那么疯狂。。。对于未来的项目,我肯定会使用WPF@我不知道。我从不使用winforms。我认为它是一种与java的东西相比的恐龙。WPF带来的数据绑定功能允许我编写真正干净的代码。这在winforms中不存在。@leo2_uru无论如何。。。如果需要,可以使用ElementHost将我的WPF内容集成到现有的winforms应用程序中。。。我的意思是,你真的不必改变所有现有的东西。
public class GridItem: PropertyChangedBase
{
public int Row { get; set; }
public int Column { get; set; }
private int? _pathIndex;
public int? PathIndex
{
get { return _pathIndex; }
set
{
_pathIndex = value;
OnPropertyChanged("PathIndex");
}
}
}
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}