Show dialog with MVVM Light toolkit - mvvm
I have a ViewModel that needs to show a modal window (using ShowDialog()) on a button click. The ViewModel catches the click command, but I don't want to do window.ShowDialog() within my ViewModel. I know there is a DialogMessage in MVVM Light, but that is used to show message boxes, not WPF modal windows.
Any ideas on how to do this?
You should use Messenger class. On the View register a message to show window, and then when you need to show it call Send method of Messenger class.
You can do something like this:
//do this in the code-behind file of your View
Messenger.Default.Register<string>(this, ShowWindow);
private void ShowWindow(string message)
{
// your logic here
}
// In the ViewModel
Messenger.Default.Send(“Some text”);
This is what I use for custom dialogs with the MVVM-Light Toolkit.
First, define these four classes somewhere in your application. The MessageBase class is part of the toolkit.
public class ShowChildWindowMessage : MessageBase { }
public class HideChildWindowMessage : MessageBase { }
public class DisplaySomeContentMessage : MessageBase { }
public class DisplaySomeOtherContentMessage : MessageBase { }
Second, you need a "child" window control. Create a XAML file with the following content:
<Window x:Class="ChildWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding Path=ChildWindowBinding, Source={StaticResource Locator}}"
Title="{Binding Path=CurrentContent.DisplayName}"
MinWidth="300" MinHeight="125" SizeToContent="WidthAndHeight"
ShowInTaskbar="False" WindowState="Normal" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner" SnapsToDevicePixels="True">
<Grid>
<ContentPresenter Content="{Binding Path=CurrentContent}" />
</Grid>
</Window>
Then add the following to the code-behind of this XAML file:
public partial class ChildWindowView : Window
{
public ChildWindowView(Window owner)
{
InitializeComponent();
Owner = owner;
Closing += (s, e) =>
{
// window reused so just hide
e.Cancel = true;
Messenger.Default.Send(new HideChildWindowMessage());
};
}
}
Third, add the following to the code-behind of your MainWindow.xaml file:
public partial class MainWindowView : Window
{
private ChildWindowView m_childWindowView;
public MainWindowView()
{
InitializeComponent();
Closing += (s, e) => ViewModelLocator.CleanUp();
Loaded += (s, e) =>
{
m_childWindowView = new ChildWindowView(this);
};
Messenger.Default.Register<ShowChildWindowMessage>(this, (msg) => m_childWindowView.ShowDialog());
Messenger.Default.Register<HideChildWindowMessage>(this, (msg) => m_childWindowView.Hide());
}
}
Fourth, define the following view model:
public class ChildWindowVM : ViewModelBase
{
private ViewModelBase m_currentContent;
public ViewModelBase CurrentContent
{
get { return m_currentContent; }
set
{
m_currentContent = value;
RaisePropertyChanged("CurrentContent");
if (m_currentContent != null)
{
Messenger.Default.Send(new ShowChildWindowMessage());
}
}
}
public ChildWindowVM()
{
Messenger.Default.Register<DisplaySomeContentMessage>(this, (msg) => CurrentContent = ViewModelLocator.SomeContentVm);
Messenger.Default.Register<DisplaySomeOtherContentMessage>(this, (msg) => CurrentContent = ViewModelLocator.SomeOtherContentVm);
}
}
Fifth, you create XAML files and view models for the content you want to display in your custom dialog. In this example, my content view models were named SomeContent and SomeOtherContent. You would replace these with what ever you want, of course.
Finally, in order for this to work you must bind your content view models to their respective XAML files by adding the following to your application resources:
<DataTemplate DataType="{x:Type viewmodels:SomeContentVM}">
<views:SomeContentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:SomeOtherContentVM}">
<views:SomeOtherContentView/>
</DataTemplate>
Once you get all this set up it is straightforward to add new content (XAML and view models) that can be displayed in your child window. To display the content, simply call the appropriate message using the Messenger class:
Messenger.Default.Send(new DisplaySomeContentMessage ());
Let me know if I need to clarify any part of this for you.
For all of you who want a really simple solution and are okay with not-100%-clean-MVVM:
I wanted to open a connect dialog from my main window and did the following
First i gave my MainWindow a name:
<Window x:Name="MainWindow">
Then i created a Command in my MainWindowViewModel:
public ICommand AddInterfaceCommand
{
get
{
return new RelayCommand<Window>((parentWindow) =>
{
var wizard = new ConnectionWizard();
wizard.Owner = parentWindow;
wizard.ShowDialog();
}
}
}
I bound my Button on the MainWindow to the Command and passed the window itself (the parent window for the dialog):
<Button Command="{Binding AddInterfaceCommand}" CommandParameter="{Binding ElementName=MainWindow}">Add interface</Button>
That's all.
Only caveat: Getting return values from the Viewmodel of the Dialog could be difficult. I don't need that feature.
You can define an interface and its implementation as follows. And ofcourse with dependency injection container, you have to do someting like this.
NInjectKernel.Bind<IMessageBoxService>().To<MessageBoxService>();
Your ViewModel will look something like this.
private IMessageBoxService _MBService;
public DropboxSettingsViewModel(IDropboxService dbService, IMessageBoxService mbService)
{
if (dbService == null)
throw new ArgumentNullException("IDropboxService is null");
_DropboxService = dbService;
if (mbService == null)
throw new ArgumentNullException("MessageBoxService is null");
_MBService = mbService;
}
Your click command execute method would be as follows.
private void ConfigureDropboxExecute(object obj)
{
_MBService.Show("Error Occured Authenticating dropbox", "Dropbox Authentication", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
public interface IMessageBoxService
{
MessageBoxResult Show(string messageBoxText);
MessageBoxResult Show(string messageBoxText, string caption);
MessageBoxResult Show(Window owner, string messageBoxText);
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);
MessageBoxResult Show(Window owner, string messageBoxText, string caption);
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button);
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult);
MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options);
MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult);
MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options);
}
using System.Windows;
public class MessageBoxService : IMessageBoxService
{
public MessageBoxResult Show(string messageBoxText)
{
return MessageBox.Show(messageBoxText);
}
public MessageBoxResult Show(Window owner, string messageBoxText)
{
return MessageBox.Show(owner, messageBoxText);
}
public MessageBoxResult Show(string messageBoxText, string caption)
{
return MessageBox.Show(messageBoxText, caption);
}
public MessageBoxResult Show(Window owner, string messageBoxText, string caption)
{
return MessageBox.Show(owner, messageBoxText, caption);
}
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
{
return MessageBox.Show(messageBoxText, caption, button);
}
public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button)
{
return MessageBox.Show(owner, messageBoxText, caption, button);
}
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
{
return MessageBox.Show(messageBoxText, caption, button, icon);
}
public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
{
return MessageBox.Show(owner, messageBoxText, caption, button, icon);
}
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
{
return MessageBox.Show(messageBoxText, caption, button, icon, defaultResult);
}
public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
{
return MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult);
}
public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
{
return MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options);
}
public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
{
return MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult, options);
}
}
Related
Click Object on Web Page in Xamarin forms
I wan to click button which created in web page. I added following code to the my project but it did execute, string always null. public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); wbWeb.Source = "https://www.facebook.com"; } private async void btnBrowser_Clicked(object sender, EventArgs e) { string str = wbWeb.EvaluateJavaScriptAsync($"document.getElementById('loginbutton').click();"); //str is null } }
Prism Button click command
Im try to open Drawer menu (Syncfusion control) via Behaviors command Xaml <Button x:Name="hamburgerButton" HeightRequest="50" WidthRequest="50" HorizontalOptions="Start" FontSize="20" BackgroundColor="#1aa1d6" > <Button.Behaviors> <b:EventToCommandBehavior EventName="Clicked" Command="{Binding HamburgerButton}" /> </Button.Behaviors> VM cs public DelegateCommand HamburgerButton { get; private set; } public QuickPartViewModel(INavigationService navigationService) { HamburgerButton = new DelegateCommand(HamburgerButton_Clicked); } public void HamburgerButton_Clicked(object sender, EventArgs e) { navigationDrawer.ToggleDrawer(); } If HamburgerButton_Clicked(object sender, EventArgs e) with arguments then i have error -// Argumment: cannot convert from 'method group' to Action if I'm remove Argumments it does't work
You're overthinking things. Just bind the command to the button. in the page: <Button Command="{Binding HamburgerCommand}" /> in the view model: public QuickPartViewModel() { HamburgerCommand = new DelegateCommand(OnHamburger); } public DelegateCommand HamburgerCommand { get; } private void OnHamburger() { navigationDrawer.ToggleDrawer(); } Give the docs a try...
How can i get specific tag?
I want to hide button of component MessageDialog, so i have decided to get tag of this button and call method hide but i don't know how to get specific tag of the element. Here is code: public class TipOfTheDayDialog extends MessageDialog { private static final Logger log = LoggerFactory.getLogger(TipOfTheDayDialog.class); public TipOfTheDayDialog(String id, String message) { super(id, "Совет дня", message, DialogButtons.OK); } #Override public void onClose(IPartialPageRequestHandler handler, DialogButton button) {} }
Just hide it with CSS. Search a proper selector and set display: none;
Read the input data and show the data in listgrid in SmartGwt
i have written a code to read the input data from textboxs and then click on submit button, this data will be show in a listgrid. Submit button click event code is here: public void onClick(ClickEvent event) {sendInfoToSever();} private void sendInfoToSever() { String Ename=firstName.getText(); String Eemail=Email.getText(); String Equerytype=rgi.getDisplayValue(); String Edesignation1=check1.getFormValue(); String Edesignation2=check2.getFormValue(); String Econtact=Contact.getText(); int indx=li1.getSelectedIndex(); String Ecountry=li1.getValue(indx); String Equerytext=queryText.getText(); showData.setWidth(475); showData.setHeight(100); ListGridField Lname= new ListGridField("name", "Name"); ListGridField Lemail= new ListGridField("email", "Email"); ListGridField Lquerytype= new ListGridField("Query Type"); ListGridField Ldesignation1= new ListGridField("Designation"); ListGridField Ldesignation2= new ListGridField("Designation"); ListGridField Lcontact= new ListGridField("Contact"); ListGridField Lcountry= new ListGridField("Country"); ListGridField Lquerytext= new ListGridField("Query Text"); showData.setFields(Lname,Lemail, Lquerytype, Ldesignation1, Ldesignation2, Lcontact, Lcountry, Lquerytext); } } how can i set the textboxes data to listgrid fields? Thanx
Try something like this: YourCustomRecordObject[] data = new YourCustomRecordObject[]{ new YourCustomRecordObject(firstName.getText(), Email.getText(), ..all other fields.. ) }; showData.setData(data); public class YourCustomRecordObject { public String name; public String email; .. all other fields.. public YourCustomRecordObject(String name, String email, ..all other fields..) { this.name = name; this.email = emal; ....... } .. getters and setters.. }
Why SimpleBeanEditorDriver returns null values
I have a SimpleBeanEditorDriver to edit my account bean but i always get null values when i edit and call flush(). i checked everything, Google documentations, stackoverflow, google groups but didn't find any problem like. did i miss something ? here is my View public class AccountCreatorViewImpl extends Composite { interface Driver extends SimpleBeanEditorDriver<Account, AccountEditor> { } interface AccountCreatorViewImplUiBinder extends UiBinder<HTMLPanel, AccountCreatorViewImpl> { } Driver driver = GWT.create(Driver.class); private static AccountCreatorViewImplUiBinder ourUiBinder = GWT.create(AccountCreatorViewImplUiBinder.class); private AccountCreatorPresenter presenter; #UiField AccountEditor accountEditor; #UiField Button create; public AccountCreatorViewImpl() { HTMLPanel rootElement = ourUiBinder.createAndBindUi(this); initWidget(rootElement); Account account = new Account(); driver.initialize(accountEditor); driver.edit(account); } #UiHandler("create") public void onCreate(ClickEvent event) { Account editedAccount = driver.flush(); if (driver.hasErrors()) { Window.alert("Has errors! ->"+driver.getErrors().toString()); } Window.alert(editedAccount.getEmail() + "/" + editedAccount.getPassword()); // presenter.create(editedAccount); } } and here is my simple editor public class AccountEditor extends Composite implements Editor<Account> { interface AccountEditorUiBinder extends UiBinder<HTMLPanel, AccountEditor> { } private static AccountEditorUiBinder ourUiBinder = GWT.create(AccountEditorUiBinder.class); #UiField TextBox email; #UiField PasswordTextBox password; public AccountEditor() { HTMLPanel rootElement = ourUiBinder.createAndBindUi(this); initWidget(rootElement); } } and this is my Account class Account public class Account implements Serializable { private String email; private String password; public Account(String email) { this.email = email; } public Account() { } public Account(String email, String password) { this.email = email; this.password = password; } public String getEmail() { return email; } public String getPassword() { return password; } } i also have the same problem with another editor in my app. actually neither one works. when i press save or create i get null values of the entity.
Try adding setEmail() and setPassword() methods to your account class