Author Topic: Beginning to hate WPF Windows almost as much as WinForms!  (Read 765 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Beginning to hate WPF Windows almost as much as WinForms!
« on: March 29, 2024, 10:39:26 AM »
My transition to WPF has been a slow one, but I was starting to get in a groove and was actually enjoying it. Until I started spending way too much time trying to get my UserControls with controls with images to actually show those images in the windows that the controls are added to. Some windows are in a different project in the same solution, others are in the same project as the control. This is something that WinForms never had a problem with, yet in WPF it seems to be a very common problem (based on my Google searches). This is at run time as well as in the Designer.

I've tried every 'solution' I could find, all with the same end result of the image not displaying.  The Build Action for the images starts out as Embedded Resource, as that is what has been working for years for the WinForms\Controls. I've changed this, based on those 'solutions', to just Embedded, Content, and None, and Copy & Don't Copy. I've changed the Source= from being just a direct path to using the pack:// option. Both show the image in the UserControl but it disappears in a consuming Window. The images are all in the Project\Resources folder and I've even added them to the project Resources.resx

Is there a WPF deity I have to worship to get these to show up correctly?  :uglystupid2: :idiot2: :crazy2:

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #1 on: March 29, 2024, 02:19:46 PM »
I set the build action to Resource for images. But there might be other issues related to WPF. Can you share some XAML?
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #2 on: March 29, 2024, 03:39:18 PM »
Oops, where I typed Embedded, Control, should have been Resource, Control.  Here is the XAML for a simple UserControl. The image is in the same project.
Code - XML: [Select]
  1. <UserControl x:Class="Quux.WPFControls.UserControls.SelectSurfaceControl"
  2.             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.             xmlns:local="clr-namespace:Quux.WPFControls.UserControls"
  7.             mc:Ignorable="d"
  8.             d:DesignHeight="90" d:DesignWidth="300" d:Background="White">
  9.     <UserControl.Resources>
  10.         <Image x:Key="PickImage" Source="pack://application:,,,/Resources/PickInDrawing.png"/>
  11.     </UserControl.Resources>
  12.     <StackPanel Margin="5" HorizontalAlignment="Stretch">
  13.         <Grid HorizontalAlignment="Stretch">
  14.             <Grid.ColumnDefinitions>
  15.                 <ColumnDefinition Width="*"/>
  16.                 <ColumnDefinition Width="25"/>
  17.             </Grid.ColumnDefinitions>
  18.             <TextBlock x:Name="label"  Text="{Binding PromptString, FallbackValue='Surface:'}" Grid.Column="0" VerticalAlignment="Bottom" Margin="2"/>
  19.             <Button x:Name="b_SelectSurface" Grid.Column="1" Margin="2"  HorizontalAlignment="Right" Content="{StaticResource PickImage}" ToolTip="Pick Object on desired Layer"
  20.                    Command="{Binding PickSurfaceInDrawing}" IsEnabled="{Binding ContainsSurfaces}" MinWidth="16"/>
  21.         </Grid>
  22.         <ComboBox x:Name="cb_Surface" Grid.Row="1" Margin="2,5" ItemsSource="{Binding Surfaces, UpdateSourceTrigger=PropertyChanged}"
  23.                  SelectedValue="{Binding SelectedSurfaceName, UpdateSourceTrigger=PropertyChanged}"  IsEnabled="{Binding ContainsSurfaces}"/>
  24.         <TextBlock x:Name="label_ElevationRange" Text="{Binding SurfaceElevationRange, UpdateSourceTrigger=PropertyChanged, FallbackValue='Elevation range: 0.00-100.00'}" Margin="10,2" FontStyle="Italic"/>
  25.     </StackPanel>
  26. </UserControl>
  27.  

Then, in the Window where the image does not display in the designer nor at runtime, still in the same project:
Code - XML: [Select]
  1.         <civilUC:SelectSurfaceControl />
  2.  

In my main project I have a window to show information about the project. In that is an image which is in the same WPF project as above. This image shows in the designer but not at runtime.
Code - XML: [Select]
  1.             <Image Grid.Column="0" Height="Auto" Width="Auto" Stretch="Fill" Source="pack://application:,,,/Quux.WPFControls;component/Resources/QuuxAboutBoxImage.png"/>
  2.  

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #3 on: March 29, 2024, 06:01:14 PM »
I can have a deeper look later this weekend.
At first glance you miss the /component/ part in line 10. Also you reference the button content to an Image object. You probably add something like x:Share=false (am not sure about the right spelling) to the Image object, else it will only show once. Things like that makes me hating wpf from the bottom of my toes.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #4 on: March 29, 2024, 07:37:01 PM »
The /component/ isn't supposed to be needed when using the /Resources in the same project. However, adding the project's assembly and /component/ actually did work for this one control/window. It also helped with some other controls. But since I was already using the assembly in the Source for the Window in a different project, it is still not finding the image at run time.

I will keep plugging away at this. Thanks for your input!

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #5 on: March 30, 2024, 06:40:05 AM »
I think it is in the pack notation. It seems you miss the assembly name. Is the DLL name 'Quux.WPFControls.dll' ?


Included is a test app with one image. It is loaded in design and runtime, in a button on a User Control on a Window. It is a 2025 project but the code is the same for prior versions.


My assembly name is 'ObjectSelection.dll' and in the image source I use this:


<Image x:Key="PickImage" Source="pack://application:,,,/ObjectSelection;component/Resources/btn-select.png" />


As far as I know (which seems to be only a small part of all WPF possibilities) you need to refer to the assembly if you use the pack notation. If you want to avoid this notation, you need to include the images in the same folder as the XAML file. Maybe there are other solutions but I have not got it working in AutoCAD in another way.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #6 on: March 30, 2024, 12:54:31 PM »
Thanks. I was using the pack information found here: https://learn.microsoft.com/en-us/dotnet/desktop/wpf/app-development/pack-uris-in-wpf?view=netframeworkdesktop-4.8 which shows this:
File   Absolute pack URI
Resource file - local assembly   "pack://application:,,,/ResourceFile.xaml"
Resource file in subfolder - local assembly   "pack://application:,,,/Subfolder/ResourceFile.xaml"
Resource file - referenced assembly   "pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml"
Resource file in subfolder of referenced assembly   "pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"

However, even with the Window and UserControl in the same assembly the only option that ended up working is the last one. And it is not working for a Window in a different assembly, so it looks like I need to have any images needed in that assembly also saved in the same assembly.

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #7 on: March 31, 2024, 06:58:33 AM »
I've read that too, but naming the assembly explicitly is the only working way. I am reading books about WPF now and it helps me to understand the designers' twists of thought, but still I struggle with the complexity. But when I have created an interactive, working dialog, I am happy. WPF is something you can both love and hate at the same time.


For my applications I always use a custom Image control. This is the class:


Code: [Select]

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;




namespace GenericSystem.WPF
{


    public class AppImage : Image
    {
        private string m_AppName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
        private string m_LocalSource = string.Empty;




        /// <summary>
        /// Get or set the local source file. It is returned to the Source Property as correct Uri.
        /// </summary>
        /// <value>Path from root and filename (/Resources/image.jpg): result is 'pack://application:,,,/[Applicationname];component/[LocalSource]'</value>
        public string LocalSource
        {
            get { return this.m_LocalSource; }


            set
            {
                if (string.IsNullOrWhiteSpace(value) == false)
                {
                    m_LocalSource = value.Trim().TrimStart('/');


                    base.Source = new BitmapImage(new Uri($"pack://application:,,,/{m_AppName};component/{m_LocalSource}", UriKind.RelativeOrAbsolute));
                }
            }
        }




        /// <summary>
        /// Reroute the property Source.
        /// </summary>
        public new Uri Source
        {
            get { throw new Exception("Use LocalSource instead Source!"); }
            set { throw new Exception("Use LocalSource instead Source!"); }
        }
    }


}


In the XAML you need a reference:


Code: [Select]

xmlns:i="clr-namespace:GenericSystem.WPF"


And then you only need to use this to show an image:


Code: [Select]
<i:AppImage LocalSource="/Resources/myImage.jpg" />


And because it is still an Image object, you can also use all the attributes like Width and Height.


It makes it much more easy to use images and this is also a perfect way to reuse the XAML in other assemblies as well, because you don't hardcode the assembly name in the XAML.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Beginning to hate WPF Windows almost as much as WinForms!
« Reply #8 on: March 31, 2024, 12:18:18 PM »
Thanks for this, Anton! Much appreciated and I will incorporate your custom image control.

Update: This helper class has solved another issue I was having with a few nested usercontrols that switch the displayed images depending on the state of a toggle button. I can finally move on to other things, THANK YOU!
« Last Edit: March 31, 2024, 12:42:11 PM by Jeff_M »