none
LDDialogues.Confirm RRS feed

  • Question

  • I was just writing a dialogue extension and noticed the dialogue doesn't take the focus.

    So I checked Litdevs and noticed the same thing.

    GraphicsWindow.Show()
    Program.Delay(3000)
    LDDialogs.Confirm("text", "title")

    Is there a way to make the GW the parent?

    Sunday, February 14, 2016 9:28 AM
    Moderator

Answers

  • Yes, I have fixed and uploaded a beta version.  This is the C# code:

                Type GraphicsWindowType = typeof(GraphicsWindow);
                Window _window = (Window)GraphicsWindowType.GetField("_window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
                InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate
                {
                    if (null != _window) return MessageBox.Show(_window, text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).ToString();
                    else return MessageBox.Show(text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).ToString();
                });
                MethodInfo method = GraphicsWindowType.GetMethod("InvokeWithReturn", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
                return method.Invoke(null, new object[] { ret }).ToString();
    

    Sunday, February 14, 2016 11:06 AM
    Moderator
  • Its all abou mixing wpf and forms - I would try to do it in wpf - that is whhat SB uses.  The class we need for _window is System.Windows.Window, not Forms version, we also need to reference the wpf assembly PresentationCore and WindowsBase.

    The following with System.Windpws.Window and the added wpf assemblies.

    Then this works:

    GraphicsWindow.Show()
    XDialogue.Password("A","b")

    But I really would consider wpf in place or forms, even f you just try a simple project to lean about it.

    using Microsoft.SmallBasic.Library;
    using Microsoft.SmallBasic.Library.Internal;
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Globalization;
    using System.Reflection;
    using System.Threading;
    using System.Windows;
    
    using System.Windows.Forms;
    using Window = System.Windows.Forms.VisualStyles.VisualStyleElement;
    
    
    namespace Jibba
    {
        /// <summary>
        /// Provides dialogue boxes
        /// </summary>
        [SmallBasicType]
        public static class XDialogue
        {
            /// <summary>
            /// A dialogue box to type in passwords. Characters are masked with *.
            /// </summary>
            /// <param name="title">a title for the dialogue box</param>
            /// <param name="text">text label for the dialogue box</param>
            /// <returns>the password</returns>
            public static Primitive Password(Primitive title, Primitive text)
            {
                Dialogue dialogue = new Dialogue();
    
                Type GraphicsWindowType = typeof(GraphicsWindow);
                System.Windows.Window _window = (System.Windows.Window)GraphicsWindowType.GetField("_window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
    
                InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate
                {
                    return dialogue.Show(title, text, _window);
                });
                MethodInfo method = GraphicsWindowType.GetMethod("InvokeWithReturn", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
                return method.Invoke(null, new object[] { ret }).ToString();
    
    
    
                // return dialogue.Show(window, title, text);
    
            }
        }
    
        class Dialogue
        {
            public string Show(string title, string text, System.Windows.Window _window)
            {     
                   
                //Form myDialogue = new Form();
    
                System.Windows.Forms.Form myDialogue = new Form();
    
                myDialogue.Width = 300;
                myDialogue.Height = 150;
                myDialogue.Text = title;
                myDialogue.MaximizeBox = false;
                myDialogue.MinimizeBox = false;
                myDialogue.StartPosition = FormStartPosition.CenterParent;
                myDialogue.Icon = Properties.Resources.feather_icon;
                myDialogue.FormBorderStyle = FormBorderStyle.FixedDialog;
    
    
                string val = "";
    
                Label txtLabel = new Label() { Left = 20, Top = 20, Text = text };
                TextBox inputBox = new TextBox() { Left = 20, Top = 50, Width = 240 };
                inputBox.PasswordChar = '*';
    
                Button confirmation = new Button() { Text = "OK", Left = 190, Width = 70, Top = 80 };
    
                confirmation.Click += (sender, e) => { myDialogue.Close(); val = inputBox.Text; };
    
                myDialogue.Controls.Add(confirmation);
                myDialogue.Controls.Add(txtLabel);
                myDialogue.Controls.Add(inputBox);
    
                if (null != _window) myDialogue.ShowDialog(new Wpf32Window(_window));
                else myDialogue.ShowDialog();
    
                //myDialogue.ShowDialog();
    
                return val;
            }
        }
    
        public class Wpf32Window : System.Windows.Forms.IWin32Window
        {
            public IntPtr Handle { get; private set; }
    
            public Wpf32Window(System.Windows.Window wpfWindow)
            {
                Handle = new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle;
            }
        }
    }
    

    Thursday, February 18, 2016 7:56 PM
    Moderator

All replies

  • Yes, I have fixed and uploaded a beta version.  This is the C# code:

                Type GraphicsWindowType = typeof(GraphicsWindow);
                Window _window = (Window)GraphicsWindowType.GetField("_window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
                InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate
                {
                    if (null != _window) return MessageBox.Show(_window, text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).ToString();
                    else return MessageBox.Show(text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).ToString();
                });
                MethodInfo method = GraphicsWindowType.GetMethod("InvokeWithReturn", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
                return method.Invoke(null, new object[] { ret }).ToString();
    

    Sunday, February 14, 2016 11:06 AM
    Moderator
  • Thanks for the sample Litdev..

    PS I find building extensions helps me learn c#.

    Sunday, February 14, 2016 8:31 PM
    Moderator
  • I've run into a snag. I'm using a form and not a MessageBox:

    public static Primitive Password(Primitive title, Primitive text)
            {
                Dialogue dialogue = new Dialogue();
    
                Type GraphicsWindowType = typeof(GraphicsWindow);
                Window window = (Window)GraphicsWindowType.GetField("window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
                
    
               return dialogue.Show(title, text);
               
            }
        }
    
        class Dialogue
        {
            public string Show(string title, string text)
            {           
                Form myDialogue = new Form();
                myDialogue.Width = 300;
                myDialogue.Height = 150;
                myDialogue.Text = title;
                myDialogue.MaximizeBox = false;
                myDialogue.MinimizeBox = false;
                myDialogue.StartPosition = FormStartPosition.CenterParent;
                myDialogue.Icon = Properties.Resources.feather_icon;
                myDialogue.FormBorderStyle = FormBorderStyle.FixedDialog;
    
                string val = "";
    
                Label txtLabel = new Label() { Left = 20, Top = 20, Text = text };
                TextBox inputBox = new TextBox() { Left = 20, Top = 50, Width = 240 };
                inputBox.PasswordChar = '*';
    
                Button confirmation = new Button() { Text = "OK", Left = 190, Width = 70, Top = 80 };
    
                confirmation.Click += (sender, e) => { myDialogue.Close(); val = inputBox.Text; };
    
                myDialogue.Controls.Add(confirmation);
                myDialogue.Controls.Add(txtLabel);
                myDialogue.Controls.Add(inputBox);
    
                myDialogue.ShowDialog();
    
                return val;
            }
        }

    Monday, February 15, 2016 7:55 AM
    Moderator
  • You are mixing forms and wpf windows - this will be harder than you think.

    The_window string inside GetField is a variable name in SmallBasicLibrary.dll (don't change to window).

    We need the call inside InvokeHelperWithReturn to run on the main program thread, and geting a windows form window handle from wpf window is not so obvious.

            public static Primitive Password(Primitive title, Primitive text)
            {
                Dialogue dialogue = new Dialogue();
    
                Type GraphicsWindowType = typeof(GraphicsWindow);
                Window _window = (Window)GraphicsWindowType.GetField("_window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
    
                InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate
                {
                    return dialogue.Show(title, text, _window);
                });
                MethodInfo method = GraphicsWindowType.GetMethod("InvokeWithReturn", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
                return method.Invoke(null, new object[] { ret }).ToString();
            }
        }
    }
    
    class Dialogue
    {
        public string Show(string title, string text, Window _window)
        {
            System.Windows.Forms.Form myDialogue = new System.Windows.Forms.Form();
            myDialogue.Width = 300;
            myDialogue.Height = 150;
            myDialogue.Text = title;
            myDialogue.MaximizeBox = false;
            myDialogue.MinimizeBox = false;
            myDialogue.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            //myDialogue.Icon = Properties.Resources.feather_icon;
            myDialogue.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            myDialogue.TopMost = true;
    
            string val = "";
    
            System.Windows.Forms.Label txtLabel = new System.Windows.Forms.Label() { Left = 20, Top = 20, Text = text };
            System.Windows.Forms.TextBox inputBox = new System.Windows.Forms.TextBox() { Left = 20, Top = 50, Width = 240 };
            inputBox.PasswordChar = '*';
    
            System.Windows.Forms.Button confirmation = new System.Windows.Forms.Button() { Text = "OK", Left = 190, Width = 70, Top = 80 };
    
            confirmation.Click += (sender, e) => { myDialogue.Close(); val = inputBox.Text; };
    
            myDialogue.Controls.Add(confirmation);
            myDialogue.Controls.Add(txtLabel);
            myDialogue.Controls.Add(inputBox);
    
            if (null != _window) myDialogue.ShowDialog(new Wpf32Window(_window));
            else myDialogue.ShowDialog();
    
            return val;
        }
    }
    
    public class Wpf32Window : System.Windows.Forms.IWin32Window
    {
        public IntPtr Handle { get; private set; }
    
        public Wpf32Window(Window wpfWindow)
        {
            Handle = new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle;
        }
    }

    Monday, February 15, 2016 8:10 PM
    Moderator
  • Thanks Litdev.
    Monday, February 15, 2016 8:17 PM
    Moderator
  • I get an error message at:

    Handle =

    newSystem.Windows.Interop.WindowInteropHelper(wpfWindow).Handle;

    It says wpfWindow: argument 1: cannot convert from styles to windows, in so many words.


    GitHub source.
    Wednesday, February 17, 2016 8:46 PM
    Moderator
  • Its all abou mixing wpf and forms - I would try to do it in wpf - that is whhat SB uses.  The class we need for _window is System.Windows.Window, not Forms version, we also need to reference the wpf assembly PresentationCore and WindowsBase.

    The following with System.Windpws.Window and the added wpf assemblies.

    Then this works:

    GraphicsWindow.Show()
    XDialogue.Password("A","b")

    But I really would consider wpf in place or forms, even f you just try a simple project to lean about it.

    using Microsoft.SmallBasic.Library;
    using Microsoft.SmallBasic.Library.Internal;
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Globalization;
    using System.Reflection;
    using System.Threading;
    using System.Windows;
    
    using System.Windows.Forms;
    using Window = System.Windows.Forms.VisualStyles.VisualStyleElement;
    
    
    namespace Jibba
    {
        /// <summary>
        /// Provides dialogue boxes
        /// </summary>
        [SmallBasicType]
        public static class XDialogue
        {
            /// <summary>
            /// A dialogue box to type in passwords. Characters are masked with *.
            /// </summary>
            /// <param name="title">a title for the dialogue box</param>
            /// <param name="text">text label for the dialogue box</param>
            /// <returns>the password</returns>
            public static Primitive Password(Primitive title, Primitive text)
            {
                Dialogue dialogue = new Dialogue();
    
                Type GraphicsWindowType = typeof(GraphicsWindow);
                System.Windows.Window _window = (System.Windows.Window)GraphicsWindowType.GetField("_window", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
    
                InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate
                {
                    return dialogue.Show(title, text, _window);
                });
                MethodInfo method = GraphicsWindowType.GetMethod("InvokeWithReturn", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
                return method.Invoke(null, new object[] { ret }).ToString();
    
    
    
                // return dialogue.Show(window, title, text);
    
            }
        }
    
        class Dialogue
        {
            public string Show(string title, string text, System.Windows.Window _window)
            {     
                   
                //Form myDialogue = new Form();
    
                System.Windows.Forms.Form myDialogue = new Form();
    
                myDialogue.Width = 300;
                myDialogue.Height = 150;
                myDialogue.Text = title;
                myDialogue.MaximizeBox = false;
                myDialogue.MinimizeBox = false;
                myDialogue.StartPosition = FormStartPosition.CenterParent;
                myDialogue.Icon = Properties.Resources.feather_icon;
                myDialogue.FormBorderStyle = FormBorderStyle.FixedDialog;
    
    
                string val = "";
    
                Label txtLabel = new Label() { Left = 20, Top = 20, Text = text };
                TextBox inputBox = new TextBox() { Left = 20, Top = 50, Width = 240 };
                inputBox.PasswordChar = '*';
    
                Button confirmation = new Button() { Text = "OK", Left = 190, Width = 70, Top = 80 };
    
                confirmation.Click += (sender, e) => { myDialogue.Close(); val = inputBox.Text; };
    
                myDialogue.Controls.Add(confirmation);
                myDialogue.Controls.Add(txtLabel);
                myDialogue.Controls.Add(inputBox);
    
                if (null != _window) myDialogue.ShowDialog(new Wpf32Window(_window));
                else myDialogue.ShowDialog();
    
                //myDialogue.ShowDialog();
    
                return val;
            }
        }
    
        public class Wpf32Window : System.Windows.Forms.IWin32Window
        {
            public IntPtr Handle { get; private set; }
    
            public Wpf32Window(System.Windows.Window wpfWindow)
            {
                Handle = new System.Windows.Interop.WindowInteropHelper(wpfWindow).Handle;
            }
        }
    }
    

    Thursday, February 18, 2016 7:56 PM
    Moderator
  • Hey thanks litdev..

    I'll do this tutorial.

    Thursday, February 18, 2016 9:51 PM
    Moderator
  • Litdev

    I'm going to add the above solution to my xtension set for future ref.

    I think I need learn a bit more about wpf before rewriting it.

    Sunday, February 21, 2016 3:10 AM
    Moderator
  • No need to rewrite anything you have using forms if they work - all I am saying is that wpf will be easier to integrate with SB in the long run (avoiding the interop confusion between forms and wpf).

    wpf and forms are 2 different tech that do basically the same thing with similar but different methods and converting between them (interop) is hard work.  Both have windows, controls, image manipulation, event handling etc etc.

    The GraphicsWindow is wpf so anything form based intercting with it needs interop (like even putting a form as its child, before you even try to put a form control on it or something else form related).

    If your forms are completely independent of the GW then you will be ok with forms in the extension - so dialogs is one reasonable use of forms in an SB extension.


    Sunday, February 21, 2016 11:35 AM
    Moderator
  • Here's a simpler sample using wpf, I think:

    using Microsoft.SmallBasic.Library;
    using System.Windows;
    
    namespace DialogueWindow
    {
        /// <summary>
        /// test dialogue window
        /// </summary>
        [SmallBasicType]
        public static class XTestWpf 
        {     
            /// <summary>
            /// Show myWindow
            /// </summary>
            public static void Show()
            {
                Window myWin = new Window();
                myWin.Title = "Hello";
                myWin.Topmost = true;
                myWin.Show();
                //MessageBox.Show("hi");          
            }
        }
    }

    What code is missing to get this to work?

    Sunday, February 21, 2016 10:00 PM
    Moderator
  • Oh this  is a minefield - the Window iteself is needs to run on STA, so use a new STA thread.  Also use ShowDialog to not immediately removethe window.

            /// <summary>
            /// Show myWindow
            /// </summary>
            public static void Show()
            {
                Thread thread = new Thread(showWindow);
                thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
                thread.Start();
                thread.Join(); //Wait for the thread to end
            }
    
            private static void showWindow()
            {
                Window myWin = new Window();
                myWin.Title = "Hello";
                myWin.Topmost = true;
                myWin.ShowDialog();
                //MessageBox.Show("hi");          
            }
    


    Sunday, February 21, 2016 10:20 PM
    Moderator