i try to bring a wpf "fire" (http://www.smartypantscoding.com/content/old-school-fire-algorithm-modern-day-wpf) Example to c++/cli. I translated it with a tool to c++/cli, but the overriden "OnRender" Event never get fired. So i see the Window like in the c# Project but without fire.
CompositionTarget_Rendering get called, and so normally InvalidateVisual() must fire the OnRender, but it doesn't. I hope u can help me =)
//the .h
#pragma once
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Globalization;
using namespace System::Xml::Linq;
using namespace System::Text;
using namespace System::Windows::Documents;
using namespace System::Windows;
using namespace System::Windows::Media;
using namespace System::Windows::Media::Imaging;
using namespace System::Threading;
#include "FireGenerator.h"
/// <summary>
/// Adorner that disables all controls that fall under it
/// </summary>
public ref class FireAdorner : Adorner
{
private:
BitmapPalette ^_pallette;
literal int DPI = 96;
FireGenerator ^_fireGenerator;
/// <summary>
/// Constructor for the adorner
/// </summary>
/// <param name="adornerElement">The element to be adorned</param>
public:
FireAdorner(UIElement^ adornerElement);
private:
void CompositionTarget_Rendering(Object ^sender, EventArgs ^e);
/// <summary>
/// Called to draw on screen
/// </summary>
/// <param name="drawingContext">The drawind context in which we can draw</param>
protected:
virtual void OnRender(System::Windows::Media::DrawingContext ^drawingContext) override;
private:
BitmapPalette ^SetupFirePalette();
private:
void InitializeInstanceFields();
};
and the .cpp
#include "StdAfx.h"
#include "FireAdorner.h"
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Globalization;
using namespace System::Xml::Linq;
using namespace System::Text;
using namespace System::Windows::Documents;
using namespace System::Windows;
using namespace System::Windows::Media;
using namespace System::Windows::Media::Imaging;
using namespace System::Threading;
FireAdorner::FireAdorner(UIElement ^adornerElement) : Adorner(adornerElement)
{
InitializeInstanceFields();
CompositionTarget::Rendering += gcnew EventHandler(this, &FireAdorner::CompositionTarget_Rendering);
}
void FireAdorner::CompositionTarget_Rendering(Object ^sender, EventArgs ^e)
{
InvalidateVisual();
}
void FireAdorner::OnRender(System::Windows::Media::DrawingContext ^drawingContext)
{
System::Windows::MessageBox::Show("render");
// only set the pallette once (dont do in constructor as causes odd errors if exception occurs)
if (_pallette == nullptr)
{
_pallette = SetupFirePalette();
}
_fireGenerator->UpdateFire();
BitmapSource ^bs = BitmapSource::Create(_fireGenerator->Width, _fireGenerator->Height, DPI, DPI, PixelFormats::Indexed8, _pallette, _fireGenerator->FireData, _fireGenerator->Width);
drawingContext->DrawImage(bs, Rect(0, 0, this->DesiredSize.Width, this->DesiredSize.Height));
}
BitmapPalette ^FireAdorner::SetupFirePalette()
{
System::Collections::Generic::List<Color> ^myList = gcnew System::Collections::Generic::List<Color>();
// seutp the basic array we will modify
for (int i = 0; i <= 255; i++)
{
myList->Add(Color());
}
for (int i = 0; i < 64; i++)
{
Color c1 = Color();
c1.R = safe_cast<Byte>(i * 4);
c1.G = safe_cast<Byte>(0);
c1.B = safe_cast<Byte>(0);
c1.A = 255;
myList[i] = c1;
Color c2 = Color();
c2.R = safe_cast<Byte>(255);
c2.G = safe_cast<Byte>(i * 4);
c2.B = safe_cast<Byte>(0);
c2.A = 255;
myList[i + 64] = c2;
Color c3 = Color();
c3.R = safe_cast<Byte>(255);
c3.G = safe_cast<Byte>(255);
c3.B = safe_cast<Byte>(i * 4);
c3.A = 255;
myList[i + 128] = c3;
Color c4 = Color();
c4.R = safe_cast<Byte>(255);
c4.G = safe_cast<Byte>(255);
c4.B = safe_cast<Byte>(255);
c4.A = 255;
myList[i + 192] = c4;
}
BitmapPalette ^bp = gcnew BitmapPalette(myList);
return bp;
}
void FireAdorner::InitializeInstanceFields()
{
_fireGenerator = gcnew FireGenerator(600, 50);
}
Initcode:
FireAdorner^ myfire = gcnew FireAdorner(MyWindow);
MyWindow->ShowDialog();
//MyWindow is a Window^ created from this Code:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Fire" Width="800" Height="200" Closing="Window_Closing">
<Grid>
<AdornerDecorator>
<DockPanel Name="dockPanel1"/>
</AdornerDecorator>
<!-- This rectangle is a hack to hide the bottom rows of the fire which look blocky
the proper solution would be to fix the rendering to leave off the bottom XX lines -->
<Rectangle Fill="Black" VerticalAlignment="Bottom"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualWidth}"
Height="8" />
</Grid>
</Window>
This solved the Problem:
old not working Initcode:
FireAdorner^ myfire = gcnew FireAdorner(MyWindow);
MyWindow->ShowDialog();
new Initcode:
DockPanel^ firebox = (DockPanel^)MyWindow->FindName("dockPanel1");
AdornerLayer^ adornerLayer = AdornerLayer::GetAdornerLayer(firebox);
adornerLayer->Add(gcnew FireAdorner(firebox));
MyWindow->ShowDialog();