Danilo
Topic Author
Posts: 17
Joined: 25 Nov 2021, 14:36

Error by instancing UserControl in Pages/UserControls per C# in Unity

30 Mar 2022, 15:30

I try to create a chat view in Unity with Noesis by setting up the barebone of the chat view in XAML and adding the single chat messages in a StackPanel. There are different types of messages. In my example here are two different types: an incoming and an outgoing text message. Both messages are UserControls that are instantiated via code and added to another UserControl (the chat view page). My problem is that I get the following error in unity every time I try to instantiate an UserControl:
[NOESIS/E] Assets/GUI/Chat/ChatView.xaml(1): Xaml not found 'Assets/GUI/Chat/IncomingTextMessage.xaml'
UnityEngine.Debug:LogError (object,UnityEngine.Object)
NoesisUnity:UnityLog (int,string) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/NoesisUnity.cs:357)
Noesis.GUI:LoadComponent (object,string) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/API/Core/NoesisGUI.cs:322)
NoesisUnity:LoadComponent (object,string) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/NoesisUnity.cs:270)
vanHope.GR.Chat.IncomingTextMessage:InitializeComponent () (at Assets/GUI/Chat/IncomingTextMessage.xaml.cs:33)
vanHope.GR.Chat.IncomingTextMessage:.ctor () (at Assets/GUI/Chat/IncomingTextMessage.xaml.cs:26)
vanHope.GR.Chat.ChatView:InstancingMessage () (at Assets/GUI/Chat/ChatView.xaml.cs:57)
vanHope.GR.Chat.ChatView:InitializeComponent () (at Assets/GUI/Chat/ChatView.xaml.cs:44)
vanHope.GR.Chat.ChatView:.ctor () (at Assets/GUI/Chat/ChatView.xaml.cs:30)
(wrapper dynamic-method) object:lambda_method (System.Runtime.CompilerServices.Closure)
Noesis.Extend:CreateInstance (intptr,intptr) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/API/Core/Extend.cs:4986)
Noesis.GUI:LoadXaml (System.IO.Stream,string) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/API/Core/NoesisGUI.cs:270)
NoesisXaml:Load () (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/NoesisXaml.cs:17)
NoesisView:LoadXaml (bool) (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/NoesisView.cs:478)
NoesisView:OnEnable () (at F:/OneDrive - vanHope Technologies/vanHope/Development/Galactic Realms/dev/NoesisGUI-Unity-3.1.4-Indie/Runtime/NoesisView.cs:609)
The following Code-Snippet is my minimal example of the code:

Here the chat view:
#if UNITY_5_3_OR_NEWER
#define NOESIS
using System;
using System.Collections.Generic;
using Noesis;
using NoesisApp;
using System.Globalization;
#else
using System;
using System.Windows;
using System.Windows.Media;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Controls;
#endif


namespace vanHope.GR.Chat
{
    /// <summary>
    /// Interaktionslogik für ChatView.xaml
    /// </summary>
    public partial class ChatView : Page
    {
        public List<ChatMessage> ChatMessages { get; set; } = new List<ChatMessage>();

        public ChatView()
        {
            InitializeComponent();
        }

#if NOESIS
        private StackPanel ChatStackPanel;
        private StackPanel MessagesStackPanel;

        private void InitializeComponent()
        {
            NoesisUnity.LoadComponent(this);
            //GUI.LoadComponent(this, "Assets/GUI/Chat/ChatView.xaml");

            ChatStackPanel = (StackPanel)FindName("ChatStackPanel");
            MessagesStackPanel = (StackPanel)FindName("MessagesStackPanel");
            InstancingMessage();
        }
#endif
        
        public void InstancingMessage()
        {
            var message = new ChatMessage
            {
                Id = 3,
                Message = "Hey, how are you?",
                MessageType = ChatMessageType.IncomingTextMessage,
                Time = DateTime.Today
            };
            MessagesStackPanel.Children.Add(new IncomingTextMessage { Message = message });
        }
        
    }

    public class ChatMessage
    {
        public long Id { get; set; }
        public string Message { get; set; }
        public ChatMessageType MessageType { get; set; }
        public DateTime Time { get; set; }
    }

    public enum ChatMessageType
    {
        IncomingTextMessage,
        OutgoingTextMessage
    }
}
And this is my IncomingTextMessage C# Code:
#if UNITY_5_3_OR_NEWER
#define NOESIS
using System;
using Noesis;
using NoesisApp;
using System.Globalization;
#else
using System;
using System.Windows;
using System.Windows.Media;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Controls;
#endif


namespace vanHope.GR.Chat
{
    /// <summary>
    /// Interaktionslogik für IncomingTextMessage.xaml
    /// </summary>
    public partial class IncomingTextMessage : UserControl
    {
        public IncomingTextMessage()
        {
            InitializeComponent();
        }
#if NOESIS
        private void InitializeComponent()
        {
            NoesisUnity.LoadComponent(this);
        }
#endif
    }
}
Am I doing an obvious mistake or is there a trick to instantiate UserControls in other UserControls or Pages via C# Code?

Thanks for helping
Danilo
 
User avatar
sfernandez
Site Admin
Posts: 3363
Joined: 22 Dec 2011, 19:20

Re: Error by instancing UserControl in Pages/UserControls per C# in Unity

04 Apr 2022, 12:46

Hi, only xaml assets that are referenced in the scene can be loaded, so if you try to create an instance of a user control where its associated xaml is not referenced by other xaml, then it will show a "Xaml not found" message. The easiest way to fix this is by adding an explicit dependency on the parent control that uses it:
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:noesis="clr-namespace:NoesisGUIExtensions"
  x:Class="Localization.MainWindow">

  <noesis:Xaml.Dependencies>
    <noesis:Dependency Source="Language-en.xaml"/>
    <noesis:Dependency Source="Language-fr.xaml"/>
    <noesis:Dependency Source="Language-jp.xaml"/>
  </noesis:Xaml.Dependencies>

</UserControl>
But I recommend you use a MVVM approach and instead of manually creating the controls, you work with data to represent your messages and DataTemplates to associate the message to the UserControl representing it:
public class TextMessage
{
  public string Text { get; set }
}
public class IncomingTextMessage : TextMessage
{
}
<DataTemplate DataType="{x:Type local:IncomingTextMessage}">
  <local:IncomingTextMessageControl Message="{Binding Text}"/>
</DataTemplate>
...
<ItemsControl x:Name="ChatMessages" ItemsSource="{Binding Messages}"/>
 
Danilo
Topic Author
Posts: 17
Joined: 25 Nov 2021, 14:36

Re: Error by instancing UserControl in Pages/UserControls per C# in Unity

12 Apr 2022, 12:59

Thanks for the helpful response, sfernandez. I read the documentation about Unity but didn't understand what it actually meant. Now I am a little bit smarter again. I also finally implemented your recommended MVVM approach. I just tweaked it by using a DataTemplateSelector to pick the right DataTemplate for incoming and outgoing messages. Works pretty fine so far.
Thanks again for the help.
 
User avatar
sfernandez
Site Admin
Posts: 3363
Joined: 22 Dec 2011, 19:20

Re: Error by instancing UserControl in Pages/UserControls per C# in Unity

12 Apr 2022, 16:01

Great to hear it, marking this as solved.

Who is online

Users browsing this forum: Bing [Bot] and 1 guest