MonkeyCat61
MonkeyCat61

Reputation: 1

React Native Windows - Native UI Component wont Display

I'm trying to create a React Native Windows application that uses native Windows components that aren't currently wrapped by the React Native Windows library. Specifically the Media Player Element.

I am new to Windows UWP programming and to React Native.

I have created a ViewManager for the MediaPlayerElement following the offical documentation and using the React Native DateTimePicker project as a reference.

The code is compiling and I can debug to see that it is being executed, however when the RN Windows application opens I cannot see my Media Player Element visibly or in the VS Live View Tree or React Native tree view tools.

I've wrapped the MediaPlayerElement using a .idl file and this is called by my MediaPlayerViewManager, which exposes the view to React Native.

My code snippets are below:


MediaPlayerView.idl

namespace MediaPlayer {

    [default_interface]
    runtimeclass MediaPlayerView : Windows.UI.Xaml.Controls.MediaPlayerElement {
        MediaPlayerView(Microsoft.ReactNative.IReactContext context);
        void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader);
    };
}

MediaPlayerView.h

#include "NativeModules.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.h"

namespace winrt::MediaPlayer::implementation {
    namespace xaml = winrt::Windows::UI::Xaml;

    class MediaPlayerView : public MediaPlayerViewT<MediaPlayerView> {
    public:
        MediaPlayerView(Microsoft::ReactNative::IReactContext const& reactContext);
        void UpdateProperties(Microsoft::ReactNative::IJSValueReader const& reader);

    private:
        Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
        bool m_updating{ false };
        void RegisterEvents();
    };
}

namespace winrt::MediaPlayer::factory_implementation {
    struct MediaPlayerView : MediaPlayerViewT<MediaPlayerView, implementation::MediaPlayerView> {};
}

MediaPlayerView.cpp

#include "pch.h"
#include "JSValueXaml.h"
#include "MediaPlayerView.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.cpp"

namespace winrt {
    using namespace Microsoft::ReactNative;
    using namespace Windows::Foundation;
}

namespace winrt::MediaPlayer::implementation {
    MediaPlayerView::MediaPlayerView(winrt::IReactContext const& reactContext) :
        m_reactContext(reactContext) {
        RegisterEvents();
    }

    void MediaPlayerView::RegisterEvents() {
        // TODO:Register events.
    }

    void MediaPlayerView::UpdateProperties(winrt::IJSValueReader const& reader) {
        m_updating = true;
        // TODO:Update properties.

        m_updating = false;
        return;
    }
}

MediaPlayerViewManager.h

#pragma once

#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"

namespace winrt::MediaPlayer::implementation {
    class MediaPlayerViewManager : public winrt::implements<
        MediaPlayerViewManager,
        winrt::Microsoft::ReactNative::IViewManager,
        winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
        winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties,
        winrt::Microsoft::ReactNative::IViewManagerWithExportedEventTypeConstants> {
    public:
        MediaPlayerViewManager();

        // IViewManager
        winrt::hstring Name() noexcept;
        winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;

        // IViewManagerWithReactContext
        winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
        void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;

        // IViewManagerWithNativeProperties
        winrt::Windows::Foundation::Collections::
            IMapView<winrt::hstring, winrt::Microsoft::ReactNative::ViewManagerPropertyType>
            NativeProps() noexcept;

        void UpdateProperties(
            winrt::Windows::UI::Xaml::FrameworkElement const& view,
            winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;

        // IViewManagerWithExportedEventTypeConstants
        winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
        winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;

    private:
        winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
    };
}

MediaPlayerViewManager.cpp

#include "pch.h"
#include "MediaPlayerViewManager.h"
#include "NativeModules.h"
#include "MediaPlayerView.h"

namespace winrt {
    using namespace Microsoft::ReactNative;
    using namespace Windows::Foundation::Collections;

    namespace xaml = winrt::Windows::UI::Xaml;
}

namespace winrt::MediaPlayer::implementation {
    MediaPlayerViewManager::MediaPlayerViewManager() {}
     
    //IViewManager
    winrt::hstring MediaPlayerViewManager::Name() noexcept {
        return L"MediaPlayerView";
    }

    xaml::FrameworkElement MediaPlayerViewManager::CreateView() noexcept {
        return winrt::MediaPlayer::MediaPlayerView(m_reactContext);
    }

    // IViewManagerWithReactContext
    winrt::IReactContext MediaPlayerViewManager::ReactContext() noexcept {
        return m_reactContext;
    }

    void MediaPlayerViewManager::ReactContext(IReactContext reactContext) noexcept {
        m_reactContext = reactContext;
    }

    // IViewManagerWithNativeProperties
    IMapView<hstring, ViewManagerPropertyType> MediaPlayerViewManager::NativeProps() noexcept {
        auto nativeProps = winrt::single_threaded_map<hstring, ViewManagerPropertyType>();

        // Insert native props here:

        return nativeProps.GetView();
    }

    void MediaPlayerViewManager::UpdateProperties(xaml::FrameworkElement const& view, 
        IJSValueReader const& propertyMapReader) noexcept {
        if (auto mediaPlayerView = view.try_as<MediaPlayerView>()) {
            mediaPlayerView->UpdateProperties(propertyMapReader);
        } else {
            OutputDebugStringW(L"Type deduction for MediaPlayerView failed.");
        }
    }

    // IViewManagerWithExportedEventTypeConstants
    ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomBubblingEventTypeConstants() noexcept {
        return nullptr;
    }

    ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomDirectEventTypeConstants() noexcept {
        return nullptr;
    }

}

ReactPackageProvider.cpp

#include "pch.h"
#include "ReactPackageProvider.h"
#include "NativeModules.h"

using namespace winrt::Microsoft::ReactNative;

// NOTE: You must include the headers of your native modules here in 
// order for the AddAttributedModules call below to find them.
#include "MediaPlayerViewManager.h"

namespace winrt::MediaPlayerProject::implementation
{

void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
{
    AddAttributedModules(packageBuilder);
    packageBuilder.AddViewManager(L"MediaPlayerViewManager", []() { return winrt::make<winrt::MediaPlayer::implementation::MediaPlayerViewManager>(); });
}

} // namespace winrt::MediaPlayerProject::implementation


MediaPlayerView.js

import React from 'react';

import { StyleSheet, View} from 'react-native';
import { requireNativeComponent } from 'react-native';

const MediaPlayerWindows = requireNativeComponent("MediaPlayerView")

const MediaPlayerView = () => {
  return(
    <View style={styles.container}>
      <MediaPlayerWindows/>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex:1,
    justifyContent:'center',
    alignItems:'center',
  }
})

export default MediaPlayerView

App.tsx

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
} from 'react-native';

import MediaPlayerView from './components/MediaPlayerView';

const App = () => {
  return (
    <SafeAreaView style={styles.App}>
      <MediaPlayerView/>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  App: {
    flexDirection:"column",
    flex:1,
    alignItems: 'center',
    justifyContent:'center',
  }
});

export default App;


What am I doing wrong to not see any output from React Native Windows?

Thank you for reading this far. This is my first Stack Overflow question and I hope I've not given too much to process.

Upvotes: 0

Views: 741

Answers (1)

MonkeyCat61
MonkeyCat61

Reputation: 1

Finally found the solution to this!

I had to implement the Microsoft.ReactNative.IViewManagerRequiresNativeLayout interface. From the React Native Windows documentation:

Your view manager is also able to declare that it wants to be responsible for its own sizing and layout. This is useful in scenarios where you are wrapping a native XAML control. To do so, implement the Microsoft.ReactNative.IViewManagerRequiresNativeLayout interface.

In the context of my example this looks like:


MediaPlayerViewManager.h

#pragma once

#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"

namespace winrt::MediaPlayer::implementation {
    class MediaPlayerViewManager : public winrt::implements<
        MediaPlayerViewManager,
        winrt::Microsoft::ReactNative::IViewManager,
        winrt::Microsoft::ReactNative::IViewManagerRequiresNativeLayout> {
    public:
        MediaPlayerViewManager();

        // IViewManager
        winrt::hstring Name() noexcept;
        winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
  
        // IViewManagerRequiresNativeLayout
        bool RequiresNativeLayout() { return true; }

    private:
        winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
    };
}


Upvotes: 0

Related Questions