Setting Caliburn IWindowmanager's Owner Property to Excel with handle HWND - excel

I have an Excel Vsto addin application in which I host WPF application build using Calibrun Micro Autofac.I have a dialog popping up the excel and I want that Pop up window's Owner to be set to this excel window.Only way I see doing this is using WindowInteropHelper Class which needs Window instance.
And I am using settings like this :
dynamic settings = new ExpandoObject();
And I show window like this :
windowManager.ShowDialog(viewModel, settings: settings);
So What should I do to set the settings.Owner Property to this excel window(Whose Handle is known) so that the Pop up window is always on top of excel window??

It looks like you are hosting a WPF application (add-in) inside Excel which is an Office application and Caliburn.Micro has a constructor in BootstrapperBase class exactly for this situation, it looks like this: BootstrapperBase(useApplication = true), so you should derive your bootstrapper from BootstrapperBase and pass in false to the base constructor. something like this:
class MyBootstrapper : BootstrapperBase {
MyBootstrapper()
: base(false)
{
}
}
Then Caliburn.Micro will set the owner property correctly for you, you don't have to worry about it. Now if you knew about this but it didn't work for then comment on this and i will give you a solution specific to your situation.
Edit: To set the owner of the created window we need to set the Owner property (which is of type Window) but the problem is that you are working with a native win32 window so you only have a handle and WPF windows don't accepts handles as Owners, and the second problem is that we don't have a reference to the created window so we can wrap it inside a WindowInteropHelper, in order to solve this i suggest the following:
Add information to the created window so we can identify it later, we can do it like this:
var settings = new ExpandoObject();
settings.Tag = "THE_ONE"
windowManager.ShowDialog(viewModel, settings: settings);
After doing so we need to get a reference to that window, so we can
do something like this: var ourWindow = Application.Current.Windows.FirstOrDefault(w => w.Tag == "THE_ONE");
Now we wrap that with a WindowInteropHelper like this: var
interopHelper = new WindowInteropHelper(ourWindow);
Now we can set owner to the native window handle like this:
interopHelper.Owner = (IntPtr) //
PUT_YOUR_NATIVE_WINDOW_HANDLE_HERE;
That's all i can help you with, i hope it works.

Related

Added custom field to projects but can't use PMProjectExt

I'm making a button to create a SOOrder from the Project. I'd like to write the newly created number back to the project, so I've added a custom field for that. It's on the form and the whole process works great.
That said, at the end when I try to write back to the project I get the following error any time I try to reference PMProjectExt:
error CS0246: The type or namespace name 'PMProjectExt' could not be found (are you missing a using directive or an assembly reference?)
Ideally my update line looks like this Base.Caches[typeof(PMProject)].SetValue<PMProjectExt.usrTEKSOOrderNbr>(TheRow, header.OrderNbr);
But even something as simple as declaring a variable (eg PMProjectExt testExt; with the PMProjectExt gets the same error.
I'm sure I'm doing something really stupid, but I can't seem to resolve it.
If you want to update a project, I recommend to instantiate the PMProject graph, assign the current record & update the user-field value. Finally persist the changes to the graph. Something like this.
ProjectEntry graph = PXGraph.CreateInstance<ProjectEntry>();
PMProject currentProject = graph.Project.Search<PMProject.contractCD>(Base,[your project nbr])
if (currentProject!=null)
{
graph.Project.Current = currentProject;
PMProjectExt projectExtension = PXCache<PMProject>.GetExtension<PMProjectExt>(currentProject);
projectExtension.usrTEKSOOrderNbr = "ABC123";
graph.Actions.PressSave();
graph.Clear();
}
So, turns out that Projects used to be Contracts. So to get the extension on Projects you need to use contracts like this:
PMProject TheRow = (PMProject)e.Row;
ContractExt TheExt = PXCache<Contract>.GetExtension<CT.ContractExt>(TheRow);
string refNbr = TheExt.UsrTEKSOOrderNbr;

Dynamics AX 2012 - Custom Lookup in a dialog

So, I am working on a class called DMFWriteExportData and trying to get it run in Batch.
I am at a point where I need to figure out a way to get rid of fieldControl and the reason being it does not let me Run the class on the server and throws an error because it is not supposed to be running on server? (not sure)
Error: "The method Dialog Control.control cannot be called from the server; use methods on the Dialog Field class instead."
-
public Object dialog()
{
DialogRunbase dialog = new DialogRunbase("#DMF372", this);
FormStringControl control;
dialogExecution = dialog.addFieldValue(extendedTypeStr(dMFExecutionId), executionId);
control = dialogExecution.fieldControl();
control.mandatory(true);
control.displayLength(24);
control.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(DMFWriteExecutionParameters, executionIdLookup), this);
control.registerOverrideMethod(methodstr(FormStringControl, modified), methodstr(DMFWriteExecutionParameters, executionIdModified), this);
dialogdescription=dialog.addFieldValue(extendedTypeStr(description),DMFExecution::find(executionId).Description);
dialogdescription.enabled(false);
return dialog;
}
I am wondering:
If it is actually true that this class cannot be set to server
when using control.registerOverrideMethod
If yes, what would be the ideal solution to overcome this situation,
is there any way I can create custom lookups? I see there is method
called registerOverrideMethod in the DialogField class.
Any help would be appreciated.
Thanks,
Khosla
The reason why you cannot (and should) run the code above in batch is because it uses dialog controls that only exist on the client side. You should never run this kind of code on server. Please check runon property of your class and set it to called from.
However, I assume you are using RunBaseBatch. If you are on AX 2012, you should use the SysOperation framework instead.
When using RunBaseBatch, all code is on the same class. This way, you are mixing client side code (main method, dialog method etc) with the code that should run on server (run method). For this reason you should set the "runon" property of the class to CalledFrom, not Server.
You can solve this by using SysOperation which applies the Model View Controller (MVC) pattern that neatly sepperates the two.
For an introduction to SysOperation, check my blog here:
AX2012: SysOperation introduction

Multiple Views for a Document in MDI Application MFC

I have a MDI application in which there are some reports and the Reports are printed and print preview in way that the was given by the MFC Printing Architecture.
But now the scenario changed and the Reports need to be formatted as a HTML File and need to be shown in the different perspective, based on a preference. I have choose a solution based on the Application architecture as there are many Document/View in my CWinApp. Created all Doc/view Templates there and the new Doc/View will be created based on the setting, once the application starts.
class CMyWinApp: public CWinApp
{
public:
virtual BOOL InitInstance();
protected:
}
BOOL CMyWinApp::InitInstance()
{
// Lot of Code Here
CreateDocumentTemplates();
}
void CMyWinApp::CreateDocumentTemplates()
{
// Some Other Doc/Templates are here
if(m_bNewView) // Based on the Setting I am creating the new View and Old Doc
{
pDocTemplate = new CMultiDocTemplate(
IDR_REPORTS,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrame), // custom MDI child frame
RUNTIME_CLASS(CMyNewView));
pDocTemplate->SetContainerInfo(IDR_TYPE_CNTR_IP);
AddDocTemplate(pDocTemplate);
}
else // This is a Old View and Doc
{
pDocTemplate = new CMultiDocTemplate(
IDR_REPORTS,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrame), // custom MDI child frame
RUNTIME_CLASS(CMyView));
pDocTemplate->SetContainerInfo(IDR_TYPE_CNTR_IP);
AddDocTemplate(pDocTemplate);
}
}
Now the scenario is, this preference can be set anytime and the further Reports need to be shown in a appropriate context.
How this can be achieved on the run time? Please help me :(
In your app class, create and save both CMultiDocTemplate pointers from your CreateDocumentTemplates function and use these to create your documents on demand(e.g override ID_FILE_NEW/ID_FILE_OPEN or similar). Look at OpenDocumentFile of CDocTemplate.
Then in your OnFileNew function or similar you can use something like this:
if(m_bNewView) {
m_pNewDocTemplate->OpenDocumentFile(...);
}
else {
m_pOldDocTemplate->OpenDocumentFile(...);
}
I would integrate CMyNewView in CMyView, if you need to switch the view dynamically. If you work with at least Visuals Studio 2008 (incl. feature pack), I recommend deriving your view class from CTabView to switch the view of the document using a handy tab next to the horizontal scrollbar of the child window.

Change visual c++ application font

How to change font in all dialog forms in a visual c++ application?
I want to set Tahoma style.
Thanks.
You can set the font for a dialog in the resource it's created from. I believe that'll change the font on all the standard controls as well. If you have custom controls, you'll have to do additional work.
Note that if you want to have the font match the default UI font for the computer, then you can use a virtual font like "MS Shell Dlg 2" which will be mapped to Tahoma on XP, and Segoe UI on Vista+.
Replacing font in each dialog of your application would be rather tedious job.
You can employ MFC to do it for you.
Check InitInstance of your app. Look at AfxEnableControlContainer();
It is being called woithout any parameter even though AfxEnableControlContainer is declared as
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager=NULL);
COccManager is a very interesting class and is used when has occ ( OLE custom controls) support, managing OLE container and site classes. All MFC applications are created by default with occ support. If you do not see AfxEnableControlContainer in the code generated by wizard, you do not have occ support enabled.
Anyway, instead using default occ implementation, use own and change it to change the font.
Derive class from COccManager. In this sample I call it CDlgOccManager. Override virtual PreCreateDialog:
virtual const DLGTEMPLATE* PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo,
const DLGTEMPLATE* pOrigTemplate);
In the implementation:
const DLGTEMPLATE* CDlgOccManager::PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo, const DLGTEMPLATE* pOrigTemplate)
{
CDialogTemplate RevisedTemplate(pOrigTemplate);
// here replace font for the template
RevisedTemplate.SetFont(_T("Tahoma"), -16);
return COccManager::PreCreateDialog (pOccDialogInfo, (DLGTEMPLATE*)RevisedTemplate.Detach());
}
Now you are changin font for all dialogs. Remember changing AfxEnableControlContainer call:
PROCESS_LOCAL(CDlgOccManager, pManager);
BOOL CDlgFontChangeApp::InitInstance()
{
AfxEnableControlContainer(pManager.GetData());
.
.
.
}
DO not forget to
#include "DlgOccManager.h"
For new verion of the MFC include afxdisp.h for older, occimpl.h for COccManager.
I just noticed something. It is not a blunder but it needs an explanation.
I have kept this code in my repository for a very, very, very long time.
It was a time when DLLs kept all data as global, making data available to all modules that loaded this dll. In order to force data to be stored in TLS area, I used PROCESS_LOCAL macro that expands to invoking CProcessLocal class that is still alive.
You can remove this macro and replace it with:
BOOL CDlgFontChangeApp::InitInstance()
{
CDlgOccManager* pManager = new CDlgOccManager();
AfxEnableControlContainer(pManager);
.
.
.
}

How to create control at runtime using app.config?

I would like to create simple objects at runtime (textbox, label, etc) and add them to a Grid in my WPF application. My problem is that I need to define these in the app.config file. I am reading in the config data by using the “ConfigurationManager.GetSection” method. Shown below is an example of the XML that defines two textboxes. The Key values are always defined as Labels so the following defines two labels called “ID:” and “Name:” and two associated TextBoxes
<HardwareControls>
<add key="ID:" value="System.Windows.Controls.TextBox"/>
<add key="Name:" value="System.Windows.Controls.TextBox"/>
</HardwareControls>
At the moment I use the following code to create a TextBox object but need to modify it so that the control types are defined by the config data and not hardcoded. Can anyone help in how I would go about doing this based on me knowing the control type as defined by a string?
TextBox tb1 = new TextBox();
tb1.Width = 100;
tb1.SetValue(Grid.ColumnProperty, 1);
tb1.SetValue(Grid.RowProperty, i);
I can also see a situation where I may want to define additional values such as the textbox width in the config file. Is there a better solution to store this in the app.config as it looks like the “GetSection” method only supports a key/value pair (I may be rog in that assumption as I haven’t read too much about this yet).
You can use Activator.CreateInstance
Example:
string typeName = "System.Windows.Controls.TextBox";
Type type = Type.GetType(typeName);
object control = Activator.CreateInstance(type); // control is your TextBox
You can use Reflection to create a type from a string name - e.g.
http://en.csharp-online.net/CSharp_FAQ:_How_create_an_instance_of_a_type_using_only_its_name
or
How can I pass an argument to a C# plug-in being loaded through Assembly.CreateInstance?

Resources