C# WPF中单元网格的最短路径优化
我目前正在尝试在WPF中创建由单元格对象组成的网格。我需要将单元格绑定到对象,对象需要在2D数组中。-我需要它是大的,可伸缩的,改变单元格的颜色,并将数据存储在对象中 我有一个实现了,但它似乎是非常缓慢的绘制网格!(100x100网格需要>10秒!) 以下是我已经制作的图片: 我正在ItemsControl中使用XAML中的数据绑定。这是我的XAML:C# WPF中单元网格的最短路径优化,c#,wpf,xaml,shortest-path,C#,Wpf,Xaml,Shortest Path,我目前正在尝试在WPF中创建由单元格对象组成的网格。我需要将单元格绑定到对象,对象需要在2D数组中。-我需要它是大的,可伸缩的,改变单元格的颜色,并将数据存储在对象中 我有一个实现了,但它似乎是非常缓慢的绘制网格!(100x100网格需要>10秒!) 以下是我已经制作的图片: 我正在ItemsControl中使用XAML中的数据绑定。这是我的XAML: <ItemsControl x:Name="GridArea" ItemsSource="{Binding Cellz}" Grid.C
<ItemsControl x:Name="GridArea" ItemsSource="{Binding Cellz}" Grid.Column="1" BorderBrush="Black" BorderThickness="0.1">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:Cell}">
<Border BorderBrush="Black" BorderThickness="0.1">
<Grid Background="{Binding CellColor}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove" >
<ei:CallMethodAction TargetObject="{Binding}" MethodName="MouseHoveredOver"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding Rows}" Columns="{Binding Columns}" MouseDown="WrapPanelMouseDown" MouseUp="WrapPanelMouseUp" MouseLeave="WrapPanelMouseLeave" >
<!--<UniformGrid.Background>
<ImageBrush/>
</UniformGrid.Background>-->
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
在我的codebehind中,我实例化了一个名为Grid的类的对象,该类使用Cell类的对象生成一个2D数组(和一个列表,这是im绑定的对象)。在用秒表检查了一下之后,我可以看出这并不花时间。这是实际的绑定和绘制网格,所以我想我的优化应该在我的XAML中进行,如果有任何优化可用的话
但为了提供一切,这里是我的代码隐藏、grid类和cell类:
public MainWindow()
{
InitializeComponent();
NewGrid = new Grid(75, 75);
DataContext = NewGrid;
}
public class Grid
{
public int Columns { get; set; }
public int Rows { get; set; }
public ObservableCollection<Cell> Cellz {get;set;}
public Cell[,] CellArray { get; set; }
public Grid(int columns, int rows)
{
Columns = columns;
Rows = rows;
Cellz = new ObservableCollection<Cell>();
CellArray = new Cell[Rows,Columns];
InitializeGrid();
}
public void InitializeGrid()
{
Color col = Colors.Transparent;
SolidColorBrush Trans = new SolidColorBrush(col);
for (int i = 0; i < Rows; i++)
{
for (int j = 0; j < Columns; j++)
{
var brandNewCell = new Cell(i, j) { CellColor = Trans};
Cellz.Add(brandNewCell);
CellArray[i, j] = brandNewCell;
}
}
}
public class Cell : INotifyPropertyChanged
{
public int x, y; // x,y location
public Boolean IsWall { get; set; }
private SolidColorBrush _cellcolor;
public SolidColorBrush CellColor
{
get { return _cellcolor; }
set
{
_cellcolor = value;
OnPropertyChanged();
}
}
public Cell(int tempX, int tempY)
{
x = tempX;
y = tempY;
}
public bool IsWalkable(Object unused)
{
return !IsWall;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(
[CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
}
public主窗口()
{
初始化组件();
新网格=新网格(75,75);
DataContext=NewGrid;
}
公共类网格
{
公共int列{get;set;}
公共整数行{get;set;}
公共可观测集合Cellz{get;set;}
公共单元格[,]ray{get;set;}
公共网格(int列、int行)
{
列=列;
行=行;
Cellz=新的可观察集合();
光线=新单元格[行,列];
InitializeGrid();
}
public void InitializeGrid()
{
颜色col=颜色。透明;
SolidColorBrush Trans=新的SolidColorBrush(col);
对于(int i=0;i
我喜欢非常简单的绑定实现,但是loadtime确实是不可接受的-任何建议都将不胜感激!好吧,我重新创建了您的示例,做了一些更改。我主要去掉了DataContext上的绑定,并为您的用例创建了一个viewmodel,它直接绑定到itemscon特罗 绘图的速度肯定低于10秒,但我想我给了你尽可能多的相关代码,以便你可以比较解决方案
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using TestSO.model;
namespace TestSO.viewmodel
{
public class ScreenViewModel : INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
private IList<Cell> cells;
public IList<Cell> Cells
{
get
{
return cells;
}
set
{
if (object.Equals(cells, value))
{
return;
}
UnregisterSource(cells);
cells = value;
RegisterSource(cells);
RaisePropertyChanged("Cells");
}
}
private int rows;
public int Rows
{
get
{
return rows;
}
set
{
if (rows == value)
{
return;
}
rows = value;
RaisePropertyChanged("Rows");
}
}
private int columns;
public int Columns
{
get
{
return columns;
}
set
{
if (columns == value)
{
return;
}
columns = value;
RaisePropertyChanged("Columns");
}
}
private Cell[,] array;
public Cell[,] Array
{
get
{
return array;
}
protected set
{
array = value;
}
}
protected void RaisePropertyChanged(string propertyName)
{
var local = PropertyChanged;
if (local != null)
{
App.Current.Dispatcher.BeginInvoke(local, this, new PropertyChangedEventArgs(propertyName));
}
}
protected void RegisterSource(IList<Cell> collection)
{
if (collection == null)
{
return;
}
var colc = collection as INotifyCollectionChanged;
if (colc != null)
{
colc.CollectionChanged += OnCellCollectionChanged;
}
OnCellCollectionChanged(collection, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, collection, null));
}
protected virtual void OnCellCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
Array = null;
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
var cell = item as Cell;
if (cell == null)
{
continue;
}
if (Array == null)
{
continue;
}
Array[cell.X, cell.Y] = null;
}
}
if (e.NewItems != null)
{
if (Array == null)
{
Array = new Cell[Rows, Columns];
}
foreach (var item in e.NewItems)
{
var cell = item as Cell;
if (cell == null)
{
continue;
}
if (Array == null)
{
continue;
}
Array[cell.X, cell.Y] = cell;
}
}
}
protected void UnregisterSource(IList<Cell> collection)
{
if (collection == null)
{
return;
}
var colc = collection as INotifyCollectionChanged;
if (colc != null)
{
colc.CollectionChanged -= OnCellCollectionChanged;
}
OnCellCollectionChanged(collection, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public ScreenViewModel()
{
}
public ScreenViewModel(int row, int col)
: this()
{
this.Rows = row;
this.Columns = col;
}
bool isDisposed = false;
private void Dispose(bool disposing)
{
if (disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
Cells = null;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
然后我稍微修改了xaml(虽然没有接管交互点),为ScreenViewModel、控制器和DataTemplate创建了资源,然后该模板也被直接添加到ItemTemplate的ItemsControl中,而不是使用DataTemplate功能(没有将此视为上述要求?)
在main.cs页面中,我加载了控制器集合与ScreenViewModel.Cells属性的链接,并加载了一些模板数据。只是一些非常基本的模拟数据(您还可以将screenmodel附加到DataContext,并在其他地方定义控制器,并更改xaml中的绑定以返回DataContext,但是通过资源,您还可以访问已经创建的实例(在initializeComponent之后)
受保护的ScreenViewModel ScreenViewModel
{
得到
{
将此.Resources[“GridViewModel”]作为ScreenViewModel返回;
}
}
受保护的CellGrid控制器
{
得到
{
将此.Resources[“CellController”]作为CellGridController返回;
}
}
受保护的空荷载()
{
var控制器=控制器;
controller.Collection.Clear();
string[]rows=colorToCellSource.Split(新字符串[]{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);
字符串行;
对于(int x=0;xusing System.Collections.Generic;
using System.Collections.ObjectModel;
using TestSO.model;
namespace TestSO.controller
{
public class GenericController<T>
{
private readonly IList<T> collection = new ObservableCollection<T>();
public IList<T> Collection
{
get
{
return collection;
}
}
public GenericController()
{
}
}
public class CellGridController : GenericController<Cell>
{
public CellGridController()
{
}
}
}
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
namespace TestSO.model
{
public class Cell : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
var local = PropertyChanged;
if (local != null)
{
Application.Current.Dispatcher.BeginInvoke(local, this, new PropertyChangedEventArgs(propertyName));
}
}
private int x;
public int X
{
get
{
return x;
}
set
{
if (x == value)
{
return;
}
x = value;
RaisePropertyChanged("X");
}
}
private int y;
public int Y
{
get
{
return y;
}
set
{
if (y == value)
{
return;
}
y = value;
RaisePropertyChanged("Y");
}
}
private bool isWall;
public bool IsWall
{
get
{
return isWall;
}
set
{
if (isWall == value)
{
return;
}
isWall = value;
RaisePropertyChanged("IsWall");
}
}
private SolidColorBrush _cellColor;
public SolidColorBrush CellColor
{
get
{
// either return the _cellColor, or say that it is transparent
return _cellColor ?? Brushes.Transparent;
}
set
{
if (SolidColorBrush.Equals(_cellColor, value))
{
return;
}
_cellColor = value;
RaisePropertyChanged("CellColor");
}
}
public Cell()
{
}
public Cell(int x, int y)
: this()
{
this.X = x;
this.Y = y;
}
}
}
<Window x:Class="TestSO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:TestSO.model"
xmlns:viewmodel="clr-namespace:TestSO.viewmodel"
xmlns:controller="clr-namespace:TestSO.controller"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<controller:CellGridController x:Key="CellController" />
<viewmodel:ScreenViewModel x:Key="GridViewModel" Rows="75" Columns="75" />
<DataTemplate x:Key="CellTemplate">
<Border BorderBrush="Black" BorderThickness="0.5">
<Grid Background="{Binding CellColor}">
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Cells,Source={StaticResource GridViewModel}}" BorderBrush="Black" BorderThickness="0.1" ItemTemplate="{StaticResource CellTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Rows="{Binding Rows,Source={StaticResource GridViewModel}}"
Columns="{Binding Columns,Source={StaticResource GridViewModel}}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
protected ScreenViewModel ScreenViewModel
{
get
{
return this.Resources["GridViewModel"] as ScreenViewModel;
}
}
protected CellGridController Controller
{
get
{
return this.Resources["CellController"] as CellGridController;
}
}
protected void Load()
{
var controller = Controller;
controller.Collection.Clear();
string[] rows = colorToCellSource.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
string row;
for (int x = 0; x < rows.Length; x++)
{
int length = rows[x].Length;
ScreenViewModel.Rows = rows.Length;
ScreenViewModel.Columns = length;
row = rows[x];
for (int y = 0; y < length; y++)
{
Cell cell = new Cell(x, y);
cell.CellColor = row[y] == '0' ? Brushes.Transparent : Brushes.Blue;
controller.Collection.Add(cell);
}
}
}
public MainWindow()
{
InitializeComponent();
if (Controller != null && ScreenViewModel != null)
{
ScreenViewModel.Cells = Controller.Collection;
Load();
}
}
<Grid>
<UniformGrid Rows="{Binding RowCount}" Columns="{Binding ColumnCount}" />
<ItemsControl ItemsSource="{Binding Cells}" .... />
</Grid>
<DataTemplate x:Key="CellTemplate" DataType="{x:Type local:Cell}">
<Border BorderBrush="Black" BorderThickness="0.1">
<Grid Background="{Binding CellColor}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove" >
<ei:CallMethodAction TargetObject="{Binding}" MethodName="MouseHoveredOver"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</Border>
</DataTemplate>
<ItemsControl ItemTemplate="{StaticResource CellTemplate}" ... />