I am currently making the switch from VB to C# AND Forms to WPF. I am looking for some help or direction on where to find how to interact with a WPF Window from a class library.
I have the Following SetUp:
And Then I have the following Class:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Drawing;
using System.Windows.Media;
using C3D_Plug_In_UI.Windows;
using System.Windows.Controls;
namespace C3D_Plug_In_Library.Classes
{
public class MessageServices
{
public static void DisplayError(string messageTitle, string messageBody, Exception errorException)
{
DisplayMessageWindow(" - Error", messageTitle, messageBody, My.Resources.imgError, Color.FromRgb(74, 74, 77), errorException);
}
public static void DisplayAttention(string messageTitle, string messageBody)
{
DisplayMessageWindow(" - Attention", messageTitle, messageBody, My.Resources.imgAttention, Color.FromRgb(37, 64, 143), null/* TODO Change to default(_) if this is not a reference type */);
}
public static void DisplayInformation(string messageTitle, string messageBody)
{
DisplayMessageWindow(" - Information", messageTitle, messageBody, My.Resources.imgInformation, Color.FromRgb(37, 64, 143), null/* TODO Change to default(_) if this is not a reference type */);
}
public static void DisplayComplete(string messageTitle, string messageBody)
{
DisplayMessageWindow(" - Complete", messageTitle, messageBody, My.Resources.imgComplete, Color.FromRgb(37, 64, 143), null/* TODO Change to default(_) if this is not a reference type */);
}
private static void DisplayMessageWindow(string headerText, string messageTitle, string messageBody, Image messageImage, Color headerColor, Exception errorException)
{
string programTitle = "Program Title";
WinMessage winMessage = new WinMessage();
winMessage.LblHeader.Text = programTitle headerText;
winMessage.PnlHeader.BackColor = headerColor;
winMessage.LblMessageTitle.Text = messageTitle;
winMessage.LblMessageBody.Text = messageBody;
winMessage.PicIcon.Image = messageImage;
if (errorException == null)
{
winMessage.Height = 160 winMessage.LblMessageBody.Height / (double)2;
winMessage.TbxException.Visible = false;
}
else
{
winMessage.Height = 300 winMessage.LblMessageBody.Height / (double)2;
winMessage.TbxException.Visible = true;
winMessage.TbxException.Text = errorException.ToString();
}
winMessage.ShowDialog();
}
}
}
I cannot seem to access the WPF window from the class. How should this be done or where can I learn the appropriate way to do this?
CodePudding user response:
It is more usual to use a pattern called mvvm with wpf. Every time you ask a question showing code manipulates UI directly like this you'll get someone tells you to use mvvm and binding so...
You should use mvvm.
In your code I guess you have no reference to the ui library from this class library so you cannot instantiate a window. If you added that reference then you might well have a problem the other way round. You might have code in your plug in ui wants to reference classes in plug in library. You can't have a refernce from both to each other as you'll get a circular reference error.
You could have a parent project references both but then this code would have to be in that.
The usual way to decouple in wpf. In fact the usual way I would recommend you create ALL UI is to use data templating.
This is a very different way to how people work in winforms.
I just posted more than is wise to post here in a different question about dialogues.
How to handle dialogs following the MVVM design pattern
Obviously, I prefer my own approach.
Data templating:
You will, obviously, need something somewhere knows about both your UI and your Code if they're going to be used together. Using the data template approach though, you could use the pub/sub pattern. Your class library can just sendmessage a dto contains all the data you need in a dialog. Wherever your mainwindow is, that can subscribe to that message and act. Instantiate UI, viewmodel etc and showdialog.
https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/messenger
Some notes on the code you have there.
In wpf, a TextBlock is the equivalent to a winforms Label.
A wpf Label is actually a content control. When you set content on a label to a string, it's internal code creates a textblock as content and sets the text property on that textblock to the content string.
In WPF it is not usual to set sizes on everything like winforms does from the designer. You would usually just let the UI "flow" and use panels.
You can size a wpf window to content and auto size rows and columns in a grid within that window if you want a window to adapt it's size. There's margin ( and padding ) on wpf controls.
Do not use large margins to position wpf controls though, use panels instead. Usually with some * proportional gridlength sizing so at least one is whatever space is left proportional to window size.
I suggest you find some videos on wpf. There's a huge learning curve, it's a very different way to work and you will likely take a lot longer if you learn as you go.