I am working on a video layout manager for a conference app. The following code is an excerpt for a Layout manager for a custom renderer. It works fine on iOS, but on Android it throws an System.InvalidOperationException: Cannot change ObservableCollection during a CollectionChanged event.
when Container.RaiseChild (localVideoControl);
is run after calling AddToContainer()
.
public class FormsLayoutManager : BaseLayoutManager
{
public AbsoluteLayout Container { get; private set; }
private bool InLayout = false;
public FormsLayoutManager (AbsoluteLayout container, LayoutPreset preset)
: base (preset)
{
Container = container;
Container.LayoutChanged += (object sender, EventArgs e) => {
if (!InLayout) {
Device.BeginInvokeOnMainThread (DoLayout);
}
};
}
public override void AddToContainer (object control)
{
Container.Children.Add ((View)control);
}
public override void RemoveFromContainer (object control)
{
Container.Children.Remove ((View)control);
}
public override void ApplyLayout ()
{
InLayout = true;
try {
var localVideoControl = (View)GetLocalVideoControl ();
var remoteVideoControls = GetRemoteVideoControls ();
var layoutWidth = (int)Container.Width;
var layoutHeight = (int)Container.Height;
// Get the new layout.
var layout = GetLayout (layoutWidth, layoutHeight, remoteVideoControls.Length);
// Apply the local video frame.
if (localVideoControl != null) {
var localFrame = layout.LocalFrame;
AbsoluteLayout.SetLayoutBounds (localVideoControl, new Rectangle (localFrame.X, localFrame.Y, localFrame.Width, localFrame.Height));
if (Mode == LayoutMode.FloatLocal) {
Container.RaiseChild (localVideoControl); //<--- System.InvalidOperationException: Cannot change ObservableCollection during a CollectionChanged event.
}
}
// Apply the remote video frames.
var remoteFrames = layout.RemoteFrames;
for (int i = 0; i < remoteFrames.Length; i++) {
var remoteFrame = remoteFrames [i];
var remoteVideoControl = (View)remoteVideoControls [i];
AbsoluteLayout.SetLayoutBounds (remoteVideoControl, new Rectangle (remoteFrame.X, remoteFrame.Y, remoteFrame.Width, remoteFrame.Height));
if (Mode == LayoutMode.FloatRemote) {
Container.RaiseChild (remoteVideoControl);
}
}
Container.ForceLayout ();
} finally {
InLayout = false;
}
}
}