我试着把wpf "fire" (http://www.smartypantscoding.com/content/old-school-fire-algorithm-modern-day-wpf)的例子带到c++/cli。我用一个工具将它翻译成c++/cli,但覆盖的"OnRender"事件从未被触发。所以我看到的窗口就像c#项目一样,但是没有火焰。
CompositionTarget_Rendering被调用,所以通常invalidatevvisuual()必须触发OnRender,但它没有。我希望你能帮助我=)
//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();
};
和。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();
//我的窗口是一个窗口^从这个代码创建:
<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>
问题解决了:
FireAdorner^ myfire = gcnew FireAdorner(MyWindow);
MyWindow->ShowDialog();
新Initcode: DockPanel^ firebox = (DockPanel^)MyWindow->FindName("dockPanel1");
AdornerLayer^ adornerLayer = AdornerLayer::GetAdornerLayer(firebox);
adornerLayer->Add(gcnew FireAdorner(firebox));
MyWindow->ShowDialog();