Associating XAML UI object with non-auto-created class?

GregJ7

Member
Joined
Nov 23, 2024
Messages
12
Programming Experience
10+
How do I associate a UI control declared in XAML with a class. From looking at the auto-generated code, a class for my Grid (class "MainWinGrid") does not exist. Similarly, the apparent way to add a class defined in code to a XAML-defined Grid is something like what is shown below (class MazeDisplay), but this gives the error that it is not in "clr-namespace:AppNamespace" (nor in "AppNamespace" if I change the local definition to that). What is the correct way?

C#:
<Window x:Class="AppNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AppNamespace"
        xmlns:loc="AppNamespace"
        mc:Ignorable="d"
        Title="MainWindow" Height="1000" Width="1250" Background="Black">
    <Grid Name="MainWinGrid" Background="Transparent" Loaded="MainWinGrid_Loaded" SizeChanged="MainWinGrid_SizeChanged" MouseLeftButtonUp="MainWinGrid_MouseLeftButtonUp">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="4*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <local:MazeDisplay Background="Transparent">
        </local:MazeDisplay>
    </Grid>
</Window>

C#:
namespace AppNamespace
{
    public class MazeDisplay : System.Windows.Controls.Panel
    {
        public MazeDisplay() : base()
        {
            Debug.WriteLine("*** In MazeDisplay() Constructor.");
        }
    }
}
 
The XAML is converted to code at build time. The bindings are usually resolved runtime. As long as your autogenerated code is built in the step before the XAML then the things will work out ... unless you are trying to use the WPF designer. That WPF designer needs the class to be generated ahead of time. For that you need to use the text template system in VS so that it will dynamically re-generate.
 
I am typing all my XAML code. Even though it has an associated display, I presume I am not using WPF Designer. What you said is good info, but I need more to understand how to transform my code into XAML UI objects with behind-code classes.
 
Do are you getting the error at build time? Or at the time you are still typing? If the latter, just ignore it until after your first build.
 
I'm not getting any errors. I never see the following debug message even though MainWinGrid is a UI component of MainWindow in the XAML. I can reference its XAML properties in code (e.g., MainWinGrid.ActualWidth), so it is recognized as a UI component, but presumably not associated with the class (since its constructor is never called).

C#:
    public partial class MainWinGrid : Grid
    {
        public MainWinGrid()
        {
            Debug.WriteLine("** In MainWinGrid() Constructor.");
        }
    } // class MainWinGrid
 
Oops, that test had MainWinGrid out of scope. If I put it in scope, then I do get an error: Ambiguity between MainWindow.MainWinGrid and MainWindow.MainWinGrid.
 
I don't think you are allowed to have more than one constructor with the same signature even with partial classes. How would the compiler determine which constructor should be called first?

Anyway, you seem to have a MainWinGrid_Loaded() method. Are you saying that is not called?
 
If I had more than one constructor with the same signature, it would be a compile-time error. The XAML for MainWinGrid does not create a class in code-behind. When I write my own class definition, there is a conflict between having the same symbols, not classes.

MainWinGrid_Loaded() is called, but it is a member of class MainWindow.
 
I finally had a chance to read your full question on a PC without having to scroll around, as well as no kids distracting me. I completely misunderstood your problem. I thought that you were trying to bind to some classes that were auto generated. On re-reading, it looks like you were trying to do your own custom controls by using something like this:
XML:
<local:MazeDisplay Background="Transparent">

I don't know why it isn't working for you. I'm not having any issues with the following code:
MainWindow.xaml:
<Window x:Class="TestWPFSubClass.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestWPFSubClass"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:MyPanel/>
    </Grid>
</Window>

MyPanel.cs:
using System.Diagnostics;
using System.Windows.Controls;

namespace TestWPFSubClass
{
    public class MyPanel : Panel
    {
        public MyPanel()
        {
            Debug.WriteLine("I'm here!");
        }
    }
}


1733008998131.png
 
this gives the error that it is not in "clr-namespace:AppNamespace" (nor in "AppNamespace" if I change the local definition to that). What is the correct way?

I got the Intellisense error before my first build:
1733009194528.png


But that makes perfect sense because the WPF Designer was trying to use a class that had not yet been compiled into an a form that the designer could use.

After successfully building at least once, the error goes away.

Also, it maybe a C/C++ affectation since I was originally a C/C++ programmer before learning C#. I always ignore what Intellisense says until after at least one successful build. This was because Intellisense for C/C++ used to be terrible in the early days of Intellisense where all the resources for it was going to the VB and C# teams.
 
Anyway, indirectly related to your problem. WPF was made in a such away that making a custom control should be a last resort. That first few choices made should be to replace the content, styles, templates, or triggers of an existing control. Its only when you truly can't get the behavior that you are looking for that you should start considering making a custom control.

See:
 
From looking at the auto-generated code, a class for my Grid (class "MainWinGrid") does not exist.

That's correct and expected behavior. By using the Name property, what happens is that the generated code creates a variable (not a class) to let you reference an instance of that particular control. See screenshots below.

There is no need for the system to generate code for the Grid because the Grid is already built into the framework.


1733018323499.png
 
What, then, is the preferred way to add custom functionality to the Grid? My idea was to put it in the class for that Grid. I'm at the point where I'd just skip the XAML and create everything dynamically, which would allow me to have a class derived from Grid with whatever features I want to add.
 
Based on what you are asking, though, it sounds like you are trying to customize things the WinForms or Qt way of doing customizing. That isn't really the WPF way. See post #11. For changing looks, you would play with the styles and templates. For changing behavior you would play with the triggers. It's only when you truly want to to do something that is not similar to something else that exists where you spin up your own control.

Also, be aware that the Grid control is really meant to be a control that handles layout, rather than a control that handles user interaction.

Also grab a copy of Josh Smith's Advanced MVVM. In it he shows various techniques, including customizing a UserControl to implement the classic Bubble Burst game.
 
It seems like my problem is in trying to hammer a non-XAML app into a XAML app. Most of my content will be dynamically generated, so I'm going to try to make it a C# / .NET / WPF app without XAML.
 
Back
Top Bottom