При решении вопроса, возник новый.
Что делаю: из ViewModel передаю коллекцию прямоугольников, вот так:
public async void Start()
{
RectItems.Clear();
CrossStitch cs = new CrossStitch()
{
BlockSize = _blockSize,
Source = _sourceImage
};
var data = await cs.Create();
foreach (var r in data)
RectItems.Add(r);
}
Получаю во View вот так:
Все замечательно работало, до того как метод Start() стал async. Теперь я получаю вместо результата, это:
Необходимо создать DependencySource в том же потоке, в котором создан DependencyObject.
Нашел только одну похожую проблему, но в ней передавалось изображение в Canvas, и проблема решалась вызовом Freeze у изображения. А как быть в моем случае?
Метод Create и прилежащие:
public Task> Create()
{
return PixelateAsync(_source);
}
private Task> PixelateTask(Bitmap source)
{
return Task.Factory.StartNew(() => Pixelate(source));
}
private Task> PixelateAsync(Bitmap source)
{
return PixelateTask(source);
}
Pixelate(source) синхронный.
Класс RectItem
public class RectItem
{
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public System.Windows.Media.Brush C { get; set; }
}
Метод Pixelate весь:
private List
List
using (var graphics = Graphics.FromImage(result))
{
graphics.PageUnit = GraphicsUnit.Pixel;
for (int x = 0; x < source.Width; x += _blockSize)
{
for (int y = 0; y < source.Height; y += _blockSize)
{
var sums = new Sums();
for (int xx = 0; xx < _blockSize; ++xx)
{
for (int yy = 0; yy < _blockSize; ++yy)
{
if (x + xx >= source.Width || y + yy >= source.Height)
{
continue;
}
var color = source.GetPixel(x + xx, y + yy);
sums.A += color.A;
sums.R += color.R;
sums.G += color.G;
sums.B += color.B;
sums.T++;
}
}
var average = Color.FromArgb(
sums.A / sums.T,
sums.R / sums.T,
sums.G / sums.T,
sums.B / sums.T);
average = GetNearestColor(average);
System.Windows.Media.Color mcolor = System.Windows.Media.Color.FromArgb(average.A, average.R, average.G, average.B);
System.Windows.Media.Brush brush = new System.Windows.Media.SolidColorBrush(mcolor);
rectangs.Add(new RectItem()
{
X = x + BlockSize,
Y = y + BlockSize,
Height = BlockSize,
Width = BlockSize,
C = brush
});
}
}
}
return rectangs;
}
Ответ
Смотрите. Проблема в том, что VM-классы создаются в фоновом потоке, это в обычной ситуации неправильно.
Но в вашем случае RectItem — не DependencyObject, а значит, он не привязан к определённому потоку. Поэтому можно пойти более простым путём: создавать этот объект где угодно. Единственная проблема, которую нужно вынести в UI — создание Brush. Но Brush является Freezable- значит, его можно также создавать где угодно, просто нужно после создания вызвать brush.Freeze();
Ещё один framework-класс — Color — тоже не является проблемой, т. к. он не является ни DependencyObject'ом, ни Freezable
Итого: просто добавьте после
System.Windows.Media.Brush brush = new System.Windows.Media.SolidColorBrush(mcolor);
строку
brush.Freeze();
Комментариев нет:
Отправить комментарий