Open dstaley opened 4 years ago
@dstaley this is already available in the playground app (packages\playground\windows\playground.sln), check it out.
@asklar Could you point to which file is implementing a native UI component? I searched for ViewManagerPropertyType
, but didn't find anything in the playground that used that API. I'm essentially looking for a more complex example of the one given in the docs. It might be that the docs are out of date with how this is being done now, and in that case an updated sample would also be appreciated!
(For reference, my goal is to add a Command bar to my application, but I figured I'd contribute to the docs in the process!)
@dstaley there are 2 main ways to include native UI in a RNW app:
MainPage.xaml
. This file defines the XAML markup for the page and includes a ReactRootView
control which will host the RN content. However, you can add any XAML controls to this page (e.g. the playground app includes a play button, comboboxes, etc., that are not being created via RNW but are created natively).
Hope this answers your question!So I actually think the CircleViewManager is more along the lines of what I think a good sample would accomplish. It looks to be managing children, which is what something like the CommandBar
would need.
I tried to follow the sample as closely as I could, and I managed to get the app to at least load and not throw an error, but it doesn't seem to be visually rendering a CommandBar or an AppBarButton. By using the XAML tree inspector I can see that it's in the tree, but the app is just a black screen. Turning on the element highlighting functions highlights the space I'd expect the CommandBar to render in, so there's definitely some layout work being done. Do UI controls need additional properties in order to render correctly? Does the renderer inject additional elements that might be causing the CommandBar to fail to render?
CommandBarViewManager.cs
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Microsoft.ReactNative;
namespace RNCommandBarSample
{
class CommandBarViewManager : IViewManager, IViewManagerWithChildren
{
public string Name => "CommandBar";
public FrameworkElement CreateView()
{
var view = new CommandBar();
return view;
}
public void AddView(FrameworkElement parent, UIElement child, long index)
{
if (parent is CommandBar view && child is AppBarButton button)
{
view.PrimaryCommands.Add(button);
}
}
public void RemoveAllChildren(FrameworkElement parent)
{
if (parent is CommandBar view)
{
view.PrimaryCommands.Clear();
}
}
public void RemoveChildAt(FrameworkElement parent, long index)
{
if (parent is CommandBar view)
{
view.PrimaryCommands.RemoveAt((int)index);
}
}
public void ReplaceChild(FrameworkElement parent, UIElement oldChild, UIElement newChild)
{
if (parent is CommandBar view && oldChild is AppBarButton oldButton && newChild is AppBarButton newButton)
{
var oldIndex = view.PrimaryCommands.IndexOf(oldButton);
view.PrimaryCommands.RemoveAt(oldIndex);
view.PrimaryCommands.Insert(oldIndex, newButton);
}
}
}
}
AppBarButtonViewManager.cs
using Microsoft.ReactNative.Managed;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace RNCommandBarSample
{
internal class AppBarButtonViewManager : AttributedViewManager<AppBarButton>
{
public override FrameworkElement CreateView()
{
var view = new AppBarButton();
view.RegisterPropertyChangedCallback(AppBarButton.LabelProperty, (obj, prop) =>
{
if (obj is AppBarButton b)
{
LabelChanged(b, b.Label);
}
});
return view;
}
[ViewManagerProperty("label")]
public void SetLabel(AppBarButton view, string value)
{
if (value != null)
{
view.SetValue(AppBarButton.LabelProperty, value);
} else
{
view.ClearValue(AppBarButton.LabelProperty);
}
}
[ViewManagerExportedDirectEventTypeConstant]
public ViewManagerEvent<AppBarButton, string> LabelChanged;
}
}
App.tsx
import React from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
const CommandBar = requireNativeComponent('CommandBar');
const AppBarButton = requireNativeComponent('AppBarButton');
const App = () => {
return (
<View>
<CommandBar>
<AppBarButton label="Button" />
</CommandBar>
</View>
);
};
export default App;
We have Playground available as a stopgap example, but we should beef up the documentation for this on the website and/or samples repo.
Proposal: Add a sample implementation of a Native UI Component that uses a built-in control
Summary
Currently, the docs for Native UI Components uses a fully custom control. It would be nice to have an example to show how developers can integrate existing UI controls instead of writing their own.
Motivation
As a React developer who is new to Windows development, it is unclear which portions of the existing sample are required if I'm using an existing XAML control. For instance, if I wanted to add a Command bar, do I need to create a class that extends from
Control
? Do I need to create a class for each different XAML tag type for Command bar? Having a through-yet-understandable example demonstrating a complex XAML control would be a great resource for developers to begin building out React versions of Windows UI components.Open Questions
Additional Comments
I'm willing to contribute this documentation provided someone can point me in the right direction (particularly how to handle in JSX components that have nested XAML components).