Issues with migration to WPF from Forms

Hello!

I am currently updating some old Windows Forms code to WPF, since the deprication of Forms in the 2024 R1 release.

In my ViewItemPlugin class i am using the GenerateViewItemManager to generate a ViewItemManager

Then, using the ViewItemManager, I am generating a ViewItemWpfUserControl using the GenerateViewItemWpfUserControl, and then doing my logic in the Control class.

class PrimaryCameraViewItemPlugin : ViewItemPlugin
{
    // ...
 
    public override ViewItemManager GenerateViewItemManager()
    {
        return new PrimaryCameraViewItemWpfManager(aLog);
    }
}
public class PrimaryCameraViewItemWpfManager : ViewItemManager
{       
    // ...
 
    public override ViewItemWpfUserControl GenerateViewItemWpfUserControl()
    {
        return new PrimaryCameraViewItemWpfUserControl(aLog);
    }
}

In my control class, I wish to control the video of a camera/stream.

From what I understand from the documentation, I “just” need to set the controller stream and camera id, which i do by the following

public partial class PrimaryCameraViewItemWpfUserControl : ViewItemWpfUserControl
{
    // ...
 
    private ImageViewerWpfControlInternal aController;
 
    // ...
 
    public override void Init()
    {
        aController = ClientControl.Instance.CreateImageViewerWpfControlInternal(WindowInformation);
 
        aController.CameraFQID = new FQID();
        aController.Initialize();				
        aController.Connect();
 
        // ...
    }
 
    public override void Close()
    {
        // ...
 
        aController.Disconnect();
        aController.Close();            
    }
 
    // ...
 
    private void UpdateCamera(Message message, FQID newCam)
    {
        aLog.Debug("New FQID received! Updating view camera and stream...");
 
        aController.Disconnect();
        aController.CameraFQID = newCam;
        aController.StreamId = new BackgroundPluginUtils(aLog).GetCameraStream(aController.CameraFQID?.ObjectId.ToString());
        aController.UpdateLayout();        
 
        aLog.Debug("Controller updated");
 
        // ...
 
        try
        {
            aLog.Debug("Initializing new camera...");
 
            aController.Initialize();
            aController.Connect();
 
            aLog.Debug("New camera connected!");
        }
        catch (Exception e)
        {
            aLog.Error("Error initializing and connecting: " + e.Message);
            aLog.Error(e.StackTrace);
        }
    }
 
    // ...
}

When debugging the code, I am getting the correct IDs from the Milestone server, and the IDs are set correctly in the control class.

I feel like there might be some event I need to fire, to tell the view to “recompile” or something, but I am having a hard time finding anything in the documentation on it…

For the sake of company security, I cannot show the full code, but the relevant code should be given in this post.

I am getting the view generated on start, but I am unable to display anything in it.

Any help is appreciated!

If you try to use the newest version of the VideoViewer (or ImageViewerClient) sample, does it work for you?

https://doc.developer.milestonesys.com/html/index.html?base=samples/componentsamples/videoviewer/readme.html&tree=tree_2.html

https://github.com/milestonesys

If it does, and you compare the code can you find something?

Hello Bo!

Thanks for your response!

I just tried the example you referenced, and it did work!

After looking at the code I am still a bit confused about what is going wrong…

I was able to spot that the example code did a

aController.Close();

Before setting the new FQID. I updated that, but with no new behavior…

From the example, I see a lot of generated code, which helps create the controllers for the two views in the example.

In my code I am initializing the controller like this

aController = ClientControl.Instance.CreateImageViewerWpfControlInternal(WindowInformation);
 
aController.CameraFQID = new FQID();
aController.Initialize();				
aController.Connect();

Could this be the problem? I do not use the Xaml files, since we need no control over how the UI looks

You should not use CreateImageViewerWpfControlInternal (generally internal means don’t use the method)

If not creating it in Xaml I guess you need..

aController = new VideoOS.Platform.Client.ImageViewerWpfControl();

Ref.

https://doc.developer.milestonesys.com/html/index.html?base=miphelp/class_video_o_s_1_1_platform_1_1_client_1_1_image_viewer_wpf_control.html&tree=tree_search.html?search=imageviewerwpfcontrol

I tried the controller that you mentioned there, still with no luck…

Here is the full code

using NLog;
using System;
using System.ComponentModel;
using System.Runtime.Remoting.Contexts;
using System.Security.Policy;
using System.Windows.Input;
using System.Windows.Shapes;
using VideoOS.Platform;
using VideoOS.Platform.Client;
using VideoOS.Platform.Messaging;
using VideoOS.Platform.Util;
using Message = VideoOS.Platform.Messaging.Message;
 
namespace EventMonitor.Client.PrimaryCameraView
{
    public partial class PrimaryCameraViewItemWpfUserControl : ViewItemWpfUserControl
    {
        private readonly ILogger aLog;
        private ImageViewerWpfControl aController;
        private object aCameraCommandReceiver;
        private object aStrechCameraVideoReceiver;
        private bool aKeepAspectRatio = true;
 
        private static readonly int aManualAssignedOverlayId = 436;
        
        public override bool Selectable => true;
 
        public PrimaryCameraViewItemWpfUserControl(ILogger log)
        {
            aLog = log;
        }
 
        public override void Init()
        {
            aLog.Debug("Initializing Primary Camera Controls...");
            aController = new ImageViewerWpfControl(WindowInformation)
            {
                CameraFQID = new FQID()
            };
            aController.Initialize();
            aController.Connect();
 
            HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
            VerticalAlignment = System.Windows.VerticalAlignment.Top;
 
            aCameraCommandReceiver = EnvironmentManager.Instance.RegisterReceiver(
                new MessageReceiver(CameraCommandListener),
                new MessageIdFilter(EventMonitorDefinition.CameraCommandMessage.ID)
            );
 
            aStrechCameraVideoReceiver = EnvironmentManager.Instance.RegisterReceiver(
                new MessageReceiver(StrechCameraVideoListener),
                new MessageIdFilter(EventMonitorDefinition.StrechCameraVideoMessage.ID)
            );
 
            aController.MouseLeftButtonUp += new MouseButtonEventHandler(ImageViewerControlClickEvent);
            
            aLog.Debug("Primary Camera Controls initialized!");
        }
 
        public override void Close()
        {
            EnvironmentManager.Instance.UnRegisterReceiver(aCameraCommandReceiver);
            EnvironmentManager.Instance.UnRegisterReceiver(aStrechCameraVideoReceiver);
            aController.MouseLeftButtonUp += new MouseButtonEventHandler(ImageViewerControlClickEvent);
            aController.Close();
            aController.Dispose();
        }
 
        private object CameraCommandListener(Message message, FQID dest, FQID sender)
        {
            EventMonitorDefinition.CameraCommandMessage mes = message.Data as EventMonitorDefinition.CameraCommandMessage;
            
            try
            {
                aLog.Debug("Recieved Camera Command: " +  mes.ToString());
            
                FQID newCam = mes.aPrimary;
 
                if(newCam == null)
                {
                    aLog.Debug("FQID recieved from message was null. Ignoring...");
                    return null;
                }
 
 
                if (aController.CameraFQID == null || aController.CameraFQID.Equals(newCam))   
                {
                    aLog.Debug("Received FQID different from existing id... updating...");
                    UpdateCamera(message, newCam);
                }
 
                if (mes.aManual)
                {
                    aController.SetOverlay(Properties.Resources.camera2_user_lock, aManualAssignedOverlayId, true, false, false, 1.0, VerticalAlignment, 
                        HorizontalAlignment, 0.0, 0.0);
                }
                else
                {
                    aController.ClearOverlay(aManualAssignedOverlayId);
                }
 
                aLog.Debug("FQID is now: " +  aController.CameraFQID?.ToString());
 
                aController.ClearOverlay(EventMonitorDefinition.aOverlayIdCrosshair);
                aController.ClearOverlay(EventMonitorDefinition.aOverlayIdManualCam);
            }
            catch (Exception e)
            {
                aLog.Error(e);
                aLog.Error(e.StackTrace);
            }
 
            return null;
        }
 
        private object StrechCameraVideoListener(Message message, FQID dest, FQID sender)
        {
            EventMonitorDefinition.StrechCameraVideoMessage mes = message.Data as EventMonitorDefinition.StrechCameraVideoMessage;
            if (mes != null)
            {
                aKeepAspectRatio = !mes.aStrech;
                aController.MaintainImageAspectRatio = aKeepAspectRatio;
            }
            return null;
        }
 
        private void UpdateCamera(Message message, FQID newCam)
        {
            aLog.Debug("New FQID received! Updating view camera and stream...");
 
            aController.Disconnect();
 
            aController = new ImageViewerWpfControl(WindowInformation)
            {
                CameraFQID = newCam,
            };
 
            try
            {
                aLog.Debug("Initializing new camera...");
 
                aController.Initialize();
                aController.Connect();
                aController.Selected = true;
 
                aLog.Debug("New camera connected!");
            }
            catch (Exception e)
            {
                aLog.Error("Error initializing and connecting: " + e.Message);
                aLog.Error(e.StackTrace);
            }
        }
 
        private void ImageViewerControlClickEvent(object sender, EventArgs e)
        {
            aLog.Debug("Primary Camera Clicked!");
 
            FireClickEvent();
 
            // Use selectRequestEvent
            aController.Selected = true;
 
            EnvironmentManager.Instance.SendMessage(new Message(EventMonitorDefinition.CameraSelectedMessage.ID,
                    new EventMonitorDefinition.CameraSelectedMessage() { aSelected = aController.CameraFQID }));
        }
        
        public override bool Maximizable
        {
            get { return false; }
        }
 
        public override bool ShowToolbar 
        {
            get { return false;}
        }
 
        public override bool Selected
        {
            get { return aController.Selected; }
        }
    }
}

. I dont know if it helps, but I do not know what is going wrong…

I am sorry I pointed to the wrong sample. I should have pointed to a plugin sample. Like the Video Preview plugin sample. https://doc.developer.milestonesys.com/html/index.html?base=samples/pluginsamples/videopreview/readme.html&tree=tree_1.html

I find it hard to understand what you are trying to achieve. I have a suspicion that you shouldn’t create your own viewitem but use the built camera viewitem. Try to have a quick look into how the Smart Client Insert Camera plugin sample can easily insert a camera in a view. https://doc.developer.milestonesys.com/html/index.html?base=samples/pluginsamples/scinsertcamera/readme.html&tree=tree_1.html