Mahapps Message Dialogs - mahapps.metro

I would like to know how to create Messages Dialogs in Mahapps. All the examples i've found were about clicking a button, but i need to create the Message from inside code (in the middle of a Try in a static async i.e.).
So... this is the code behind the MainWindow (From the GIT examples)
public async void ShowMessageDialog(object sender, RoutedEventArgs e)
{
// This demo runs on .Net 4.0, but we're using the Microsoft.Bcl.Async package so we have async/await support
// The package is only used by the demo and not a dependency of the library!
var mySettings = new MetroDialogSettings()
{
AffirmativeButtonText = "Hi",
NegativeButtonText = "Go away!",
FirstAuxiliaryButtonText = "Cancel",
ColorScheme = MetroDialogOptions.ColorScheme
};
MessageDialogResult result = await this.ShowMessageAsync("Hello!", "Welcome to the world of metro!",
MessageDialogStyle.AffirmativeAndNegativeAndSingleAuxiliary, mySettings);
if (result != MessageDialogResult.FirstAuxiliary)
await this.ShowMessageAsync("Result", "You said: " + (result == MessageDialogResult.Affirmative ? mySettings.AffirmativeButtonText : mySettings.NegativeButtonText +
Environment.NewLine + Environment.NewLine + "This dialog will follow the Use Accent setting."));
}
How i could i call ShowMessageDialog from any other ViewModels and show the Dialog over that MainWindow?
Thanks!

You can get the ActiveWindow Like so :
var metroWindow = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(x => x.IsActive) as MetroWindow;
I would suggest to make a MessageService that retrive the Active Window and manage all the messages of your application. Furthermore, you should Implement a interface (IMessageService) if you want the ability to Unit Test your code.

Related

Command handling in Qooxdoo multi window application

I want to create a Qooxdoo application that consists of a Desktop with multiple Windows. The Desktop (and not each Window) also has a (common) ToolBar.
Now I want to have a command to "save" the document of the active window. This command can be triggered by the keyboard shortcut "Ctrl+S" as well as a button on the toolbar.
To handle the "Ctrl+S" to reach the currently active window the qx.ui.command.GroupManager (as described by https://qooxdoo.org/documentation/v7.5/#/desktop/gui/interaction?id=working-with-commands and https://qooxdoo.org/qxl.demobrowser/#ui~CommandGroupManager.html) is supposed to be the best solution. And I could easily implement that in my code.
But now I'm struggling to make the toolbar save button also call the save command of the currently active window as I don't know how to bind it correctly to the GroupManager.
An example code to get started in the playground https://qooxdoo.org/qxl.playground/:
// NOTE: run this script only once. Before running it again you need to reload
// the page as it seems that the commands are accumulation and not reset.
// I guess that this is a bug in the Playground
const root = this.getRoot();
qx.Class.define('test.Application',
{
extend : qx.application.Standalone,
members: {
main: function() {
const layout = new qx.ui.layout.VBox(5);
const container = new qx.ui.container.Composite(layout);
root.add(container, {edge: 0});
const windowManager = new qx.ui.window.Manager();
const desktop = new qx.ui.window.Desktop(windowManager);
this._manager = new qx.ui.command.GroupManager();
const menuBar = new qx.ui.menubar.MenuBar();
let menu = new qx.ui.menu.Menu();
///////////////////////////
// TODO: Call _doSave() of the active window!
let saveMenuButton = new qx.ui.menu.Button('Save','#MaterialIcons/save/16');
///////////////////////////
menu.add(saveMenuButton);
var fileMenu = new qx.ui.menubar.Button('File', null, menu);
menuBar.add(fileMenu);
const toolBar = new qx.ui.toolbar.ToolBar();
///////////////////////////
// TODO: Call _doSave() of the active window!
let saveToolBarButton = new qx.ui.toolbar.Button('Save','#MaterialIcons/save/16');
///////////////////////////
toolBar.add(saveToolBarButton);
container.add(menuBar,{flex:0});
container.add(toolBar,{flex:0});
container.add(desktop,{flex:1});
this._foo1 = new test.Window('foo1', this);
desktop.add(this._foo1);
this._foo1.open();
this._foo1.moveTo(100,20);
this._foo2 = new test.Window('foo2', this);
desktop.add(this._foo2);
this._foo2.open();
this._foo2.moveTo(200,100);
this._foo3 = new test.Window('foo3', this);
desktop.add(this._foo3);
this._foo3.open();
this._foo3.moveTo(300,180);
},
getGroupManager() {
return this._manager;
}
}
});
qx.Class.define('test.Window', {
extend: qx.ui.window.Window,
construct(windowName, controller) {
this.base(arguments, windowName);
this._name = windowName;
let commandGroup = new qx.ui.command.Group();
const cmd = new qx.ui.command.Command("Ctrl+S");
cmd.addListener('execute', this._doSave, this);
commandGroup.add('save', cmd);
controller.getGroupManager().add(commandGroup);
this.addListener('changeActive', () => {
if (this.isActive()) {
controller.getGroupManager().setActive(commandGroup);
}
}, this);
},
members: {
_doSave() {
alert("save " + this._name);
}
}
});
a = new test.Application();
How should the saveMenuButton.setCommand() and saveToolBarButton.setCommand() should look like to always call the command of the active window?
You can control a current active window via Desktop class:
let saveToolBarButton = new qx.ui.toolbar.Button('Save');
saveToolBarButton.addListener("click", function(){
desktop.getActiveWindow()._doSave();
}, this);
Would be great for your solution imo is to create a separate command and add this command to buttons:
const saveActiveWindowCommand = new qx.ui.command.Command();
saveActiveWindowCommand.addListener("execute", function(){
desktop.getActiveWindow()._doSave();
}, this);
let saveMenuButton = new qx.ui.menu.Button('Save');
saveMenuButton.setCommand(saveActiveWindowCommand);
let saveToolBarButton = new qx.ui.toolbar.Button('Save');
saveToolBarButton.setCommand(saveActiveWindowCommand);
EDIT:
You could set commands dynamically for "Main Panel" menu buttons. Because there is only one instance of command pressing "Ctrl+S" will trigger only one command but maybe you would like that main bar save buttons have extra logic.
You have in application class next method which will be called from window class when changeActive event happens.
setSaveCommand(command){
this.saveMenuButton.setCommand(command);
this.saveToolBarButton.setCommand(command);
},
and in your Window class:
if (this.isActive()) {
controller.setSaveCommand(cmd);
controller.getGroupManager().setActive(commandGroup);
}

Can I remove the 'carrot' (upside down triangle) created by the ComboBoxListViewSkin?

When implementing the java ComboBoxListViewSkin class to manage the popup listener of my ComboBox, this adds a 'carrot' to the upper left corner of the ComboBox (see below). If I remove this class implementation it goes away. I'm using the CombBoxListViewSkin's class popup listener to prevent the [SPACE] from selecting and closing the ComboBox when pressed which allows the [SPACE] character to be typed as part of an AutoComplete class.
This is all the code involved in managing and allowing the [SPACE] to work as part of AutoComplete class -and works great. I've tried searching the ComboBoxListViewSkin class for methods or properties that may prevent this, but nothing addresses this. I thought maybe the COMBO_BOX_STYLE_CLASS might offer something but everything really only manages the displaying, adding or removing items. Since the code below is the minimal necessary to recreate the issue, this will not perform the auto-complete function, but it demonstrates that removing and re-implementing the ComboBoxListViewSkin class causes the issue.... or appears to.
// Main method calling
public class Main extends Application{
public static void main(String[] args) {
launch();
}
public void start(Stage stage) throws Exception {
ComboBox cmb = new ComboBox();
cmb.getItems().setAll("One", "One Two", "One Two Three");
new ComboBoxAutoComplete(cmb);
Scene scene = new Scene(new StackPane(cmb));
stage.setScene(scene);
stage.setTitle("Test GUI");
stage.setWidth(300);
stage.setHeight(300);
stage.show();
}
}
// ComboBoxAutoComplete class with ComboBoxListViewSkin initialization
// Minimal of ComboBoxAutoComplete class constructor
import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import java.util.stream.Stream;
#SuppressWarnings("ALL")
public class ComboBoxAutoComplete<T> {
private ComboBox<T> cmb;
private String filter = "";
private ObservableList<T> originalItems;
private ComboBoxListViewSkin cbSkin;
public ComboBoxAutoComplete(final ComboBox<T> cmb) {
this.cmb = cmb;
originalItems = FXCollections.observableArrayList(cmb.getItems());
cbSkin = new ComboBoxListViewSkin(cmb);
// Aside from the variable declaration and initialization... this
// is the only ComboBoxListViewSkin code to handle the [SPACE]
cbSkin.getPopupContent().addEventFilter(KeyEvent.KEY_PRESSED, (event) -> {
if (event.getCode() == KeyCode.SPACE) {
filter += " ";
event.consume();
}
});
}
}
My expectation is for the ComboBox to look like all the other ComboBoxes in the application GUI. Although it is a minor issue, to the user I believe it may look like an issue with the application is going on.
Resolved: As Fabian suggested above, I added a cmb.setSkin(cbSkin) after the initialization and before the event filtering and it worked. Thought I would post so others would see it was resolved.
cbSkin = new ComboBoxListViewSkin(cmb);
cmb.setSkin(cbSkin); // <------------- ADDED
cbSkin.getPopupContent().addEventFilter(KeyEvent.KEY_PRESSED, (event) -> {
if (event.getCode() == KeyCode.SPACE) {
filter += " ";
event.consume();
}
});

Hyperlink.Click not being executed

I'm writing a Windows Phone Mango app. I have a hyperlink that contains email addresses. I want it to show a message box on tap:
Hyperlink href = new Hyperlink();
href.Click += (s, r) =>
{
MessageBox.Show("href clicked");
};
// add href to RichTextBox
When I click on the hyperlink in the emulator, nothing happens. The click += line is hit in a debugger, but the new EmailComposeTask() line isn't.
What am I doing wrong? Is Click not the event I want?
Update: I switched EmailComposeTask to MessageBox to verify that this issue isn't related to the email compose task not running on the emulator. I've reproduced this issue on my device.
The following code works:
GestureService.GetGestureListener(href); // adding this makes it work
href.Click += (s, r) =>
{
MessageBox.Show("href clicked");
new EmailComposeTask() { To = entireLink.Value }.Show();
};
href.Inlines.Add(new Run() { Text = entireLink.Value });
GetGestureListener creates a gesture listener if it doesn't already exist.
You should use HyperlinkButton Class, Hyperlink is a class used with rich text document rendering.
Following code is runs on device. text is RichTextBox object.
var linkText = new Run() { Text = "Link text" };
var link = new Hyperlink();
link.Inlines.Add(linkText);
link.Click += (o, e) =>
{
MessageBox.Show("Link clicked");
};
var paragraph = new Paragraph();
paragraph.Inlines.Add(link);
text.Blocks.Add(paragraph);

Can I put a Button in a RichTextBox in Silverlight 4?

I would like to allow users to put a System.Windows.Controls.Button in the System.Windows.Controls.RichTextBox. The button would do a pre-defined thing.
I figured out how to do this. It's called an InlineUIContainer you can do something like this to get it working. Although it doesn't save it into the Xaml
var p = new Paragraph();
var inlineUIContainer = new InlineUIContainer() { Child = new Button() { Content = "This is a Button!" } };
p.Inlines.Add(inlineUIContainer);
_richTextBox.Blocks.Add(p);

How can I create a fluent interface for defining Dialog Boxes?

I am looking for examples and experience of using fluent interface to define simple Dialog Boxes (and other UI elements).
(I may need to add support for custom Dialog Boxes to an in-house programming language and I think a fluent interface may be the best way of doing it)
The UI system will be build on Winforms OR WPF if that effects your answers.
What if the interface is not fluent and I changed the question to just a “a simple to use (and read) API..” that does not depend on the use of a “drag and drop” UI designer.
I think the result will be fluent to some extend, e.g
Textbox(“name”). Labelled(“Person
Name”). Column(1)
Textbox(“notes”). Labelled(“Notes”).
Multiline(4). Column(1).ToColumn(3)
However the interface does not have to be a single line
This "How to make Databinding type safe and support refactoring"
gives a good starting point for a fluent interface for databinding.
I built a fluent interface for my dialog boxes, something along the lines of:
var result = Dialog
.Buttons(buttons.Ok, buttons.Cancel)
.Title("")
.Text("")
.Show();
if ( result == DialogResult.Ok) {
//...
}
I also had one for taking in an enum something like this:
var result = Dialog(of EnumName)
.Text("")
.Title("")
.Show();
if ( result == EnumName.Value1 ) {
//...
}
Which generated the buttons from the enum, and returned the selected buttons enum value.
Edit: Added from comments:
The form it shows has its width calculated to fit all the buttons in one row.
It has an method for adding extra controls.
The layout is made from flow layout panels (one horizontal for buttons. one vertical for text and other controls)
The general layout is of a standard messagebox.
It has another option for Auto Accelerating the buttons.
Summary of Methods:
.Buttons(paramarray of DialogResult)
.FromEnum<T>(enum)
.Title(text)
.Text(text)
.Control(control)
.AutoAccelerate
.Icon(image)
.Show() as T
The examples given so far do nothing to reduce the complexity of the task; they only trade one syntax for another (almost equally verbose) one. If you invest the time to create a fluent interface, leverage it to actually improve the expressiveness of your API instead of just jiggling syntactic sugar. Raise the level of abstraction from the default primitives (buttons, modalities,...) to templates, visual inheritance chains and behaviors.
I haven't totally thought this through yet, but something along the lines of:
Dialog
.WithStandardColors()
.WithTitleOf("ChooseSomething")
.WithButtonSet<OkCancel>()
.Show();
or
Dialog
.UseErrorFormatting
.SetTitleTo("Uh Oh")
.Show()
This question has been driving me crazy for a few days. I think a question you might need to ask is "why should I make a fluent API for dialog boxes?"
When you look at popular fluent APIs you'll notice something that's common with them in that it aids a user to be able to fluently read a line of code. Almost like a sentence. Observe:
From Ninject:
Bind(typeof(IWeapon)).To(typeof(Sword));
From Moq:
mock.Setup(foo => foo.Execute("ping"))
.Returns(() => calls)
.Callback(() => calls++);
From the mother of all fluent APIs, Linq:
var query = Products
.Where(p => p.Name.Contains("foo")
.OrderBy(p => p.Name);
These are good APIs that provide almost a sentence structure to their use.
As another example, how is this:
Dialog.Buttons(buttons.Ok, buttons.Cancel).Title("").Text("")
More readable and more useful than
new Dialog()
{
Buttons = Buttons.OkCancel,
Title = "",
Text = ""
};
And this is just a simple example. I noticed you are asking how to stuff things like layout, etc all in one line of code. My goodness your lines are going to be long.
I think you need to decide if you really think a fluent API is gaining you anything here. All I see are methods that set properties on a dialog box and don't provide any readability or value.
LINQ example of a fluent interface:
var customerTurnover = allOrders
.Where (o.CustomerID == CustomerID)
.Sum (o => o.Amount);
Basically, it is a way to design interfaces to minimize verbosity and provide a natural and well readable way to combine operations in order to accomplish much with little code.
An imaginary example for the dialog boxes domain:
DialogBoxAPI
.ModalDialogBox ()
.RoundCornersStyle ()
.BackgroundColor (RGB (200, 200, 200))
.TextColor (0, 0, 0)
.MessageText ("What shall we decide?")
.OKButton ()
.CancelButton ();
Which would generate a dialog box with the supplied characteristics. Is that what you are looking for?
I have good experience with extension methods and single "context" of fluent calling in combination with anonymous methods.
I hope example will be more clear:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TcKs.FluentSample {
class FluentSample {
Form CreateDialogBox() {
var frm = new Form();
frm.AddTextField( "Simple text field:" )
.AddTextField( "Advanced text field:", null, txt => txt.BackColor = Color.Red )
.AddTextField( "Complex text field:", lbl => {
lbl.Click += ( _sender, _e ) => MessageBox.Show( lbl, "Some informative text.", "Help" );
lbl.Font = new Font( lbl.Font, FontStyle.Underline );
lbl.Cursor = Cursors.Hand;
},
txt => {
txt.TextChanged += ( _sender, _e ) => txt.BackColor = txt.TextLength > 0 ? SystemColors.Window : Color.Red;
txt.DoubleClick += ( _sender, _e ) => { /* TODO: show lookup dialog */ };
txt.AddErrorProvider();
} )
.AddButton( btn => btn.Click += ( _sender, _e ) => frm.Close() );
return frm;
}
}
// contains standard extension methods for fluent creation of control
static class StandardControlFluentExtensionMethods {
// this extension method create button and add them to parent
public static T AddButton<T>( this T parent ) where T : Control {
return AddButton<T>( parent, (Action<Button>)null );
}
// this extension method create button and add them to parent, then call initMethod
public static T AddButton<T>( this T parent, Action<Button> initButton ) where T : Control {
var button = new Button();
parent.Controls.Add( button );
if ( null != initButton ) { initButton( button ); }
return parent;
}
}
// contains specialized extension methods for fluent creation of control
static class SpecializedControlFluentExtensionMethods {
public static T AddCloseButton<T>( this T parent, Action<Button> initButton ) where T : Control {
return parent.AddButton( btn => {
var frm = btn.FindForm();
if ( null != frm ) { frm.Close(); }
if ( null != initButton ) { initButton( btn ); }
} );
}
}
// contains data-driven extension methods for fluent creation of control
static class DataDrivenControlFluentExtensionMethods {
public static TParent AddTextField<TParent>( this TParent parent, string title ) where TParent : Control {
return AddTextField<TParent>( parent, title, (Action<Label>)null, (Action<TextBox>)null );
}
public static TParent AddTextField<TParent>( this TParent parent, string title, Action<Label> initTitle, Action<TextBox> initEditor ) where TParent : Control {
Label lblTitle = new Label();
// lblTitle .....
if ( null != initTitle ) { initTitle( lblTitle ); }
TextBox txtEditor = new TextBox();
// txtEditor ....
if ( null != initEditor ) { initEditor( txtEditor ); }
return parent;
}
public static TParent AddErrorProvider<TParent>( this TParent parent ) where TParent : Control {
return AddErrorProvider( parent, (Action<ErrorProvider>)null );
}
public static TParent AddErrorProvider<TParent>( this TParent parent, Action<ErrorProvider> initErrorProvider ) where TParent : Control {
// create and/or initilaize error provider
return parent;
}
}
}

Resources