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:
namespace MediaPlayer {
[default_interface]
runtimeclass MediaPlayerView : Windows.UI.Xaml.Controls.MediaPlayerElement {
MediaPlayerView(Microsoft.ReactNative.IReactContext context);
void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader);
};
}
#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> {};
}
#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;
}
}
#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 };
};
}
#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;
}
}
#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
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
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.
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 };
};
}