Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - allenlooplee/DialogUtils: A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app. · GitHub
Skip to content

Repository files navigation

DialogUtils

Poster

Dialogs are a little bit tricky in the world of MVVM because it can be easy to break the basic rule of MVVM by introducing dialogs inside view models. For example, you want to show a dialog when a user clicks a button which is typically data bound to a command of a view model, and the code to show the dialog is within the implementation of that command. If you create an instance of the dialog within that code, you're making your view model aware of a view, and hence the break of the basic rule of MVVM.

There's no simple way to deal with dialogs in MVVM. ReactiveUI's solution is to abstract the dialogs as interactions. Material Design In XAML Toolkit's solution is DialogHost. I'm using the latter in Aclass for Windows but extend it a little bit to make it easy to work with Microsoft MVVM Toolkit and Microsoft Dependency Injection/.NET Generic Host.

Super Quick Start

If you're going to start a new project, it is highly recommended to use the VSIX template installer to install a clean project template for your Visual Studio.

  1. Find and install "dialogutils" in Visual Studio's Manage Extensions dialog box.
  2. Search "dialogutils" and create a new project with the "Material Design WPF App with DialogUtils" project template in Visual Studio.
  3. Hit F5 to run the app.

Note that the project template further leverages Material Design Extensions for MaterialWindow and AppBar.

Getting Started

If you're going to use DialogUtils in an existing project that already has Material Design In XAML Toolkit installed and configured, below is the guide.

  1. Search and install DialogUtils in NuGet Package Manager.
  2. In MainWindow.xaml, insert a <DialogHost/> between <Window/> and it's original child.
<Window>
<md:DialogHostIdentifier="MainHost">
<!-- original child -->
</md:DialogHost>
</Window>
  1. Register DialogHostService using the AddDialogHostService extension method and MainViewModel in App.xaml.cs. If you're using .NET Generic Host, you can use the UseDialogHostService extension method instead on the IHostBuilder object.
publicpartialclassApp:Application{publicApp(){Ioc.Default.ConfigureServices(ConfigureServices());}privatestaticIServiceProviderConfigureServices(){varservices=newServiceCollection();services.AddDialogHostService();services.AddTransient<MainViewModel>();returnservices.BuildServiceProvider();}}
  1. Setup MainViewModel as MainWindow's DataContext. If you're using .NET Generic Host, you might already have both MainViewModel and MainWindow registered in the container. In this case you can inject MainViewModel in MainWindow's constructor.
publicMainWindow(){InitializeComponent();DataContext=Ioc.Default.GetService<MainViewModel>();}
  1. Inject IDialogHostService in MainViewModel's constructor, save it as a private member for showing dialogs within any command implementation.
publicclassMainViewModel:ObservableObject{privateIDialogHostService_dialogHostService;privateICommand_showMessageCommand;publicICommandShowMessageCommand=>_showMessageCommand??(_showMessageCommand=newRelayCommand(ShowMessageImpl));privateasyncvoidShowMessageImpl(){await_dialogHostService.ShowMessageAsync(dialogIdentifier:"MainHost",message:"Hello, World");}publicMainViewModel(IDialogHostServicedialogHostService){_dialogHostService=dialogHostService;}}

Usage

  1. How to show a message?

The simplest way to do so is call the ShowMessageAsync on an instance of IDialogHostService usually injected via constructor as below. The dialogIdentifier and message parameters are required; the others such as header are optional.

await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message);
  1. How to show a message with OK and Cancel buttons and return whether the user clicks the OK button?

Passing true to the isNegativeButtonVisible parameter of ShowMessageAsync will show both OK and Cancel buttons. The return value will be true if the user clicks OK button; otherwise false. The text of both buttons can also be customized by using the affirmativeButtonText and negativeButtonText parameters of ShowMessageAsync respectively.

varresult=await_dialogHostService.ShowMessageAsync(DialogHostIdentifier,Message,isNegativeButtonVisible:true);
  1. How to get input from user?

Call ShowInputAsync as below which will show a dialog with a TextBox inside. If the user types some text within the TextBox and clicks OK button, the method will return that as a string; otherwise, null. If you want also to show an existing value in the TextBox, you can use the third parameter which is currently null in the below code.

varresult=await_dialogHostService.ShowInputAsync(DialogHostIdentifier,Message,null,Header);
  1. How to show a progress dialog?

Call ShowProgressAsync as below which will show a small dialog with an indeterminate progress ring inside. You'll need to close the dialog manually by calling CloseDialog on an instance of IDialogHostService with the same DialogHostIdentifier.

_dialogHostService.ShowProgressAsync(DialogHostIdentifier);

If you want also a cancel button on the dialog, you can pass true to the cancellable parameter. In this case, clicking that cancel button will close the current progress dialog.

ShowProgressAsync returns the view model used by the current progress dialog. If you want to change the value of the progress ring, you can pass false to the isIndeterminate parameter and increase the value of the Value property as below. Note that you can also use the Close method of the view model to close the current progress dialog.

varvm=_dialogHostService.ShowProgressAsync(DialogHostIdentifier,isIndeterminate:false);for(doubled=0;d<100;d+=.5){vm.Value=d;awaitTask.Delay(10);}vm.Close();
  1. How to show a custom dialog?

Let's say you have a view named EditContactView and a view model named EditContactViewModel registered as transient in App's ConfigureServices method as below. Note that views are required to inherit from UserControl.

services.AddTransient<EditContactViewModel>();services.AddTransient<EditContactView>();

And tell DialogHostService that they relate to each other via Configure method as below. Note that if you create a project with the VSIX template, the ConfigureDialogHostService method is already created for you.

privatestaticIDialogHostServiceConfigureDialogHostService(IServiceProviderservices){vardialogHostService=newDialogHostService(services);dialogHostService.Configure<EditContactViewModel,EditContactView>();returndialogHostService;}

Now you can show it via ShowDialogAsync method as below. As you can see, you tell it which view model to use, it'll find the corresponding view to show. You can also initialize the view model by passing a lambda.

await_dialogHostService.ShowDialogAsync<EditContactViewModel>(DialogHostIdentifier,
vm =>vm.Init(Contact));

Usually we inject a view model into a view via constructor as below. In this case DialogHostService will use the view model you injected. Otherwise, it will get one from the container and associate it to the view for you.

publicEditContactView(EditContactViewModel viewModel){InitializeComponent();DataContext=viewModel;}
  1. How to know if a dialog is opened or being closed?

You can register DialogHostMessage with WeakReferenceMessenger's Register method, and then check the DialogIdentifier property or the ViewModelType property. These are actually two dimensions because one dialog host can be used for multiple dialogs and one dialog can be hosted in multiple dialog hosts. To know whether the dialog host or a dialog view model is opened or being closed, you can check the DialogHostEvent property to see if it's DialogHostEvent.Opened or DialogHostEvent.Closing respectively.

Thanks

About

A small library that provides a simple yet complete way to use DialogHost from Material Design in XAML in a WPF MVVM app.

Topics

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages