c++wpfoverridingcommand-line-interfaceonrender

C++/cli override OnRender Event wpf


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>

Solution

  • 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();