How can i populate dropdown fom database in dnn - dotnetnuke

I want to add new page in the DNN site which populates two dropdown for Country and State from the database.
Please suggest how we can do this?

Here I show you how to create dynamic pages using DNN module. For more information refer this link.
First of all open your DNN website in Visual Studio. You can see the DesktopModules folder in your root directory, right click on the directory and add new directory give it to name as your module name, for example "CountryState". Now right click on the CountryState folder and Add->Add New Item->Select Web User Control and give it to name as your module name like "CountryState.ascx", it will show you CountryState.ascx and CountryState.ascx.cs files in DesktopModules/CountryState folder.
Next step to update inherit class "System.Web.UI.UserControl" to "PortalModuleBase". This is because of the PortalModuleBase class defines a custom base class inherited by all desktop portal modules within the Portal. The PortalModuleBase class defines portal specific properties that are used by the portal framework to correctly display portal module.
Now logged-In in your website using your Host credential.
In DNN panel, go-to Host->Extensions.
Click on Create New Module button on right top corner of the Extensions Page.
Create New Module button open a popup window with Create Module Form DropDownList. Select Control from that Drop-Down.
It will show you form, select your .ascx web user control in that from as respected folder path and click on Create Module button.
Finally Drag-N-Drop module on your page.
Enjoy! ;)

I have a blog article with code sample on how to accomplish this in DNN.
CASCADING COUNTRY / STATE DROPDOWNS: A STUDY IN DOTNETNUKE 7 WEBAPI SERVICES AND AJAX

Keval's solution is OK for a quick and dirty solution, but for something a bit more sustainable, I prefer to keep my modules in their own solution apart from DNN. I then use the project post build events to copy the required code over to the bin and desktop module folders. This makes source control easier and opening up the solution much quicker.
The build scripts for the different file extensions
xcopy "$(ProjectDir)*.ascx" C:\Webs\Properteez\DesktopModules\$(ProjectName)\*.ascx /S /C /Y /D
xcopy "$(ProjectDir)*.css" C:\Webs\Properteez\DesktopModules\$(ProjectName)\*.css /S /C /Y /D
xcopy "$(ProjectDir)*.txt" C:\Webs\Properteez\DesktopModules\$(ProjectName)\*.txt /S /C /Y /D
xcopy "$(ProjectDir)App_LocalResources\*.resx" C:\Webs\Properteez\DesktopModules\$(ProjectName)\App_LocalResources\*.resx /S /C /Y /D
xcopy "$(ProjectDir)Styles\*.css" C:\Webs\Properteez\DesktopModules\$(ProjectName)\Styles\*.css /S /C /Y /D
xcopy "$(ProjectDir)Scripts\*.js" C:\Webs\Properteez\DesktopModules\$(ProjectName)\Scripts\*.js /S /C /Y /D
xcopy "$(ProjectDir)Images\*.*" C:\Webs\Properteez\DesktopModules\$(ProjectName)\Images\*.* /S /C /Y /D
xcopy "$(TargetDir)$(TargetFileName)" C:\Webs\Properteez\bin /C /Y /Q /D
Also,
populates two dropdown for Country and State from the database
Communicating with the DB can be done the "DNN way" with PetaPoco.
Model example (This will need to map directly yo your DB table):
#region Usings
using System;
using DotNetNuke.ComponentModel.DataAnnotations;
using DotNetNuke.Common.Utilities;
#endregion
namespace Properteez.Data.Entities
{
[TableName("Sync_Property")]
[PrimaryKey("PropertyId", "PropertyId")]
public class Property
{
#region Properties
public int PropertyId { get; set; }
public string Name { get; set; }
public string ShortDesc { get; set; }
public int UserId { get; set; }
public bool IsDeleted { get; set; }
// You can use the [IgnoreColumn] attribute if a property does not map to a DB field
}
}
Repository method examples:
public static Property Get(int id)
{
Property item;
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
item = rep.GetById(id);
}
return item;
}
public static List<Property> GetAllSinceLastSync(DateTime lastSyncDate)
{
List<Property> items;
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
items = rep.Get()
// Filter list to valid properteez that have been added or changed since last sync
.Where(p => (!p.IsDeleted && !p.IsSold) && p.LastModifiedOnDate >= lastSyncDate)
.ToList();
}
return items;
}
public static List<Property> GetAll()
{
List<Property> items;
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
items = rep.Get().ToList();
}
return items;
}
public static int Create(Property item)
{
item.CreatedOnDate = DateTime.Now;
item.LastModifiedOnDate = DateTime.Now;
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
rep.Insert(item);
}
return item.PropertyId;
}
public static void Update(Property item)
{
item.LastModifiedOnDate = DateTime.Now;
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
rep.Update(item);
}
}
public static void Delete(Property item)
{
using (IDataContext ctx = DataContext.Instance())
{
var rep = ctx.GetRepository<Property>();
rep.Delete(item);
}
}
Debug
You can debug the application by building (copy over .dlls to bin folder of DNN instance), going to Debug>Attach to process and selecting the "W3wp" process
Note, you will need to be running Visual Studio as admin.

Related

EpiServer - Restrict what blocks can go in what folders

In EpiServer 11, I want to enforce what blocks get can added to which folders under blocks. Following this article:
https://talk.alfnilsson.se/2015/12/07/creating-a-content-folder-that-only-allows-specific-content-types/
This works, but the folders can only be one level deep. That is I cant add any custom folders that reside inside other custom folders. Is there a way to control this?
This was due to a lack of understanding about configuration. This was my folder:
[ContentType(DisplayName = "Settings Folder", GUID = "1422f7b1-a6aa-485f-a7f3-4049c9343f06", Description = "")]
[AvailableContentTypes(Availability.Specific, Include = new [] { typeof(SiteSettingsBlock), typeof(HeaderSettingsBlock), typeof(FooterSettingsBlock)})]
public class SettingsFolder : ContentFolder
{
}
All I needed to do was add Content Folder as an available type:
[ContentType(DisplayName = "Settings Folder", GUID = "1422f7b1-a6aa-485f-a7f3-4049c9343f06", Description = "")]
[AvailableContentTypes(Availability.Specific, Include = new [] { typeof(SiteSettingsBlock), typeof(HeaderSettingsBlock), typeof(FooterSettingsBlock), typeof(ContentFolder)})]
public class SettingsFolder : ContentFolder
{
}

2sxc - Use shared classes in SxcApiController

If I use that code for my ScxApiController
public class InstallController : SxcApiController
{
[HttpGet]
[AllowAnonymous]
public object Test()
{
return new MyObj();
}
}
public class MyObj
{
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
All work fine, but I want to be able to put MyObj code to separete file. If I just move this code to separate file the class is not found. How I can move this code outside the main class that still work?
==== Solution 1 ==========================================
1 - Move MyObj file to /App_Code folder
2 - Add namespace in this new file
3 - Use MyObj with namespace or add using
This is OK for custom project but don't know how to pack this file to module installer
Basically what you want to do is beyond the standard compile-on-demand setup. Usually you would put this in a visual studio project and build DLLs. This is of course more complex than what 2sxc is usually used for, but we also do this a lot when we have sophisticated business logic.

How to use Dapper's SqlBuilder?

I can't find any documentation or examples I can follow to use the SqlBuilder class.
I need to generate sql queries dynamically and I found this class. Would this be the best option?
the best place to start is to checkout the dapper source code from its github repo and have a look at the SqlBuilder code. The SqlBuilder class is only a 200 lines or so and you should be able to make an informed choice on whether it is right for your needed.
An other option is to build your own. I personally went down this route as it made sense. Dapper maps select querys directly to a class if you name your class properties the same as your database or add an attribute such as displayName to map from you can use reflection to get the property names. Put there names and values into a dictionary and you can genarate sql fairly easy from there.
here is something to get you started:
first an example class that you can pass to your sqlbuilder.
public class Foo
{
public Foo()
{
TableName = "Foo";
}
public string TableName { get; set; }
[DisplayName("name")]
public string Name { get; set; }
[SearchField("fooId")]
public int Id { get; set; }
}
This is fairly basic. Idea behind the DisplayName attribute is you can separate the properties out that you want to include in your auto generation. in this case TableName does not have a DisplayName attribute so will not be picked up by the next class. however you can manually use it when generating your sql to get your table name.
public Dictionary<string, object> GetPropertyDictionary()
{
var propDictionary = new Dictionary<string, object>();
var passedType = this.GetType();
foreach (var propertyInfo in passedType.GetProperties())
{
var isDef = Attribute.IsDefined(propertyInfo, typeof(DisplayNameAttribute));
if (isDef)
{
var value = propertyInfo.GetValue(this, null);
if (value != null)
{
var displayNameAttribute =
(DisplayNameAttribute)
Attribute.GetCustomAttribute(propertyInfo, typeof(DisplayNameAttribute));
var displayName = displayNameAttribute.DisplayName;
propDictionary.Add(displayName, value);
}
}
}
return propDictionary;
}
This method looks at the properties for its class and if they are not null and have a displayname attribute will add them to a dictionary with the displayname value as the string component.
This method is designed to work as part of the model class and would need to be modified to work from a separate helper class. Personally I have it and all my other sql generation methods in a Base class that all my models inherit from.
once you have the values in the dictionary you can use this to dynamically generate sql based on the model you pass in. and you can also use it to populate your dapper DynamicParamaters for use with paramiterized sql.
I hope this helps put you on the right path to solving your problems.

How to read, edit and export word documents in WPF without Microsoft office being installed?

I have an WPF application that relies heavily on manipulating documents; I want to know if there is a library that works independetly from Microsoft Office Word and that provides the following features:
Reading word documents (*.doc or rtf will be suffisiant, *.docx will be perfect)
Enable me to edit the document from my WPF app
Enable me to export again the document into other formats (word, excel, pdf)
Free :)
Thanks in advance.
I will try to answer in order:
Reading: This article is good for you.
Edit & export: May be this library works for you.
Free: The most difficult part of your question. You can do it for free using Interop Assemblies for Office. But controls for free... Many controls not free around the net.
Hope it helps.
I was faced with similar question some years ago. I had Windows forms application with some 20 reports and about 100 users and I needed to generate Word documents from application. Application was installed on a server. My first attempt was done by using Office interop, but it caused problems with performance and all kinds of unpredictable exceptions. So I started to look for alternatives and I soon landed with OpenXML.
First idea was that our team would use OpenXML SDK to generate and manipulate documents. It soon turned out that the learning curve was way too steep and our management wasn't willing to pay for the extra work.
So we started to look for alternatives. We didn't find any useful free library and so we tried some commercial ones (Aspose, Docentric). Aspose gave great results, but it was too expensive. Docentric's license is cheaper and the product performed well in Word document generation, so we finally decided to purchase it.
WHAT IT TAKES TO GENERATE A DOCUMENT FROM A TEMPLATE
Install Docentric Toolkit (you can get 30 day trial version for free)
In your VisualStudio project ad references to 4 Docentric dlls, which you can find in installation folder C:\Program Files (x86)\Docentric\Toolkit\Bin
Include Entity Framework via NuGet package If you will fill data from SQL database into the Word document
Prepare Word template, where you define layout and include fields which will get filled with data at document generation (see on-line documentation how to do it).
It doesn't take much code to prepare the data to be merged with the template. In my example I prepare order for customer "BONAP" from Northwind database. Orders include customer data, order details and product data. Data model also includes header and footer data.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Docentric.Word;
using System.Diagnostics;
namespace WordReporting
{
// Report data model
public class ReportData
{
public ReportData()
{ }
public string headerReportTemplatetName { get; set; }
public string footerDateCreated { get; set; }
public string footerUserName { get; set; }
public List<Order> reportDetails { get; set; }
}
// model extensions
public partial class Order
{
public decimal TotalAmount { get; set; }
}
public partial class Order_Detail
{
public decimal Amount { get; set; }
}
// Main
class Program
{
static void Main(string[] args)
{
// variable declaration
List<Order> orderList = new List<Order>();
string templateName = #"c:\temp\Orders_template1.docx";
string generatedDocument = #"c:\temp\Orders_result.docx";
// reading data from database
using (var ctx = new NorthwindEntities1())
{
orderList = ctx.Orders
.Include("Customer")
.Include("Order_Details")
.Include("Order_Details.Product")
.Where(q => q.CustomerID == "BONAP").ToList();
}
// collecting data for the report
ReportData repData = new ReportData();
repData.headerReportTemplatetName = templateName;
repData.footerUserName = "<user name comes here>";
repData.footerDateCreated = DateTime.Now.ToString();
repData.reportDetails = new List<Order>();
foreach (var o in orderList)
{
Order tempOrder = new Order();
tempOrder.Customer = new Customer();
tempOrder.OrderID = o.OrderID;
tempOrder.Customer.CompanyName = o.Customer.CompanyName;
tempOrder.Customer.Address = o.Customer.Address;
tempOrder.Customer.City = o.Customer.City;
tempOrder.Customer.Country = o.Customer.Country;
tempOrder.OrderDate = o.OrderDate;
tempOrder.ShippedDate = o.ShippedDate;
foreach (Order_Detail od in o.Order_Details)
{
Order_Detail tempOrderDetail = new Order_Detail();
tempOrderDetail.Product = new Product();
tempOrderDetail.OrderID = od.OrderID;
tempOrderDetail.ProductID = od.ProductID;
tempOrderDetail.Product.ProductName = od.Product.ProductName;
tempOrderDetail.UnitPrice = od.UnitPrice;
tempOrderDetail.Quantity = od.Quantity;
tempOrderDetail.Amount = od.UnitPrice * od.Quantity;
tempOrder.TotalAmount = tempOrder.TotalAmount + tempOrderDetail.Amount;
tempOrder.Order_Details.Add(tempOrderDetail);
}
repData.reportDetails.Add(tempOrder);
}
try
{
// Word document generation
DocumentGenerator dg = new DocumentGenerator(repData);
DocumentGenerationResult result = dg.GenerateDocument(templateName, generatedDocument);
// start MS Word and show generated document
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "WINWORD.EXE";
startInfo.Arguments = "\"" + generatedDocument + "\"";
Process.Start(startInfo);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
// wait for the input to terminate the application
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
}
}

Open directory dialog

I want the user to select a directory where a file that I will then generate will be saved. I know that in WPF I should use the OpenFileDialog from Win32, but unfortunately the dialog requires file(s) to be selected - it stays open if I simply click OK without choosing one. I could "hack up" the functionality by letting the user pick a file and then strip the path to figure out which directory it belongs to but that's unintuitive at best. Has anyone seen this done before?
You can use the built-in FolderBrowserDialog class for this. Don't mind that it's in the System.Windows.Forms namespace.
using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
}
If you want the window to be modal over some WPF window, see the question How to use a FolderBrowserDialog from a WPF application.
EDIT: If you want something a bit more fancy than the plain, ugly Windows Forms FolderBrowserDialog, there are some alternatives that allow you to use the Vista dialog instead:
Third-party libraries, such as Ookii dialogs (.NET 4.5+)
The Windows API Code Pack-Shell:
using Microsoft.WindowsAPICodePack.Dialogs;
...
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
Note that this dialog is not available on operating systems older than Windows Vista, so be sure to check CommonFileDialog.IsPlatformSupported first.
I created a UserControl which is used like this:
<UtilitiesWPF:FolderEntry Text="{Binding Path=LogFolder}" Description="Folder for log files"/>
The xaml source looks like this:
<UserControl x:Class="Utilities.WPF.FolderEntry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<Button Margin="0" Padding="0" DockPanel.Dock="Right" Width="Auto" Click="BrowseFolder">...</Button>
<TextBox Height="Auto" HorizontalAlignment="Stretch" DockPanel.Dock="Right"
Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</DockPanel>
</UserControl>
and the code-behind
public partial class FolderEntry {
public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(FolderEntry), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(FolderEntry), new PropertyMetadata(null));
public string Text { get { return GetValue(TextProperty) as string; } set { SetValue(TextProperty, value); }}
public string Description { get { return GetValue(DescriptionProperty) as string; } set { SetValue(DescriptionProperty, value); } }
public FolderEntry() { InitializeComponent(); }
private void BrowseFolder(object sender, RoutedEventArgs e) {
using (FolderBrowserDialog dlg = new FolderBrowserDialog()) {
dlg.Description = Description;
dlg.SelectedPath = Text;
dlg.ShowNewFolderButton = true;
DialogResult result = dlg.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK) {
Text = dlg.SelectedPath;
BindingExpression be = GetBindingExpression(TextProperty);
if (be != null)
be.UpdateSource();
}
}
}
}
As stated in earlier answers, FolderBrowserDialog is the class to use for this. Some people have (justifiable) concerns with the appearance and behaviour of this dialog. The good news is that it was "modernized" in NET Core 3.0, so is now a viable option for those writing either Windows Forms or WPF apps targeting that version or later (you're out of luck if still using NET Framework though).
In .NET Core 3.0, Windows Forms users [sic] a newer COM-based control that was introduced in Windows Vista:
To reference System.Windows.Forms in a NET Core WPF app, it is necessary to edit the project file and add the following line:
<UseWindowsForms>true</UseWindowsForms>
This can be placed directly after the existing <UseWPF> element.
Then it's just a case of using the dialog:
using System;
using System.Windows.Forms;
...
using var dialog = new FolderBrowserDialog
{
Description = "Time to select a folder",
UseDescriptionForTitle = true,
SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
+ Path.DirectorySeparatorChar,
ShowNewFolderButton = true
};
if (dialog.ShowDialog() == DialogResult.OK)
{
...
}
FolderBrowserDialog has a RootFolder property that supposedly "sets the root folder where the browsing starts from" but whatever I set this to it didn't make any difference; SelectedPath seemed to be the better property to use for this purpose, however the trailing backslash is required.
Also, the ShowNewFolderButton property seems to be ignored as well, the button is always shown regardless.
Ookii folder dialog can be found at Nuget.
PM> Install-Package Ookii.Dialogs.Wpf
And, example code is as below.
var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
if (dialog.ShowDialog(this).GetValueOrDefault())
{
textBoxFolderPath.Text = dialog.SelectedPath;
}
More information on how to use it: https://github.com/augustoproiete/ookii-dialogs-wpf
For those who don't want to create a custom dialog but still prefer a 100% WPF way and don't want to use separate DDLs, additional dependencies or outdated APIs, I came up with a very simple hack using the Save As dialog.
No using directive needed, you may simply copy-paste the code below !
It should still be very user-friendly and most people will never notice.
The idea comes from the fact that we can change the title of that dialog, hide files, and work around the resulting filename quite easily.
It is a big hack for sure, but maybe it will do the job just fine for your usage...
In this example I have a textbox object to contain the resulting path, but you may remove the related lines and use a return value if you wish...
// Create a "Save As" dialog for selecting a directory (HACK)
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.InitialDirectory = textbox.Text; // Use current value for initial dir
dialog.Title = "Select a Directory"; // instead of default "Save As"
dialog.Filter = "Directory|*.this.directory"; // Prevents displaying files
dialog.FileName = "select"; // Filename will then be "select.this.directory"
if (dialog.ShowDialog() == true) {
string path = dialog.FileName;
// Remove fake filename from resulting path
path = path.Replace("\\select.this.directory", "");
path = path.Replace(".this.directory", "");
// If user has changed the filename, create the new directory
if (!System.IO.Directory.Exists(path)) {
System.IO.Directory.CreateDirectory(path);
}
// Our final value is in path
textbox.Text = path;
}
The only issues with this hack are :
Acknowledge button still says "Save" instead of something like "Select directory", but in a case like mines I "Save" the directory selection so it still works...
Input field still says "File name" instead of "Directory name", but we can say that a directory is a type of file...
There is still a "Save as type" dropdown, but its value says "Directory (*.this.directory)", and the user cannot change it for something else, works for me...
Most people won't notice these, although I would definitely prefer using an official WPF way if microsoft would get their heads out of their asses, but until they do, that's my temporary fix.
Ookii Dialogs includes a dialog for selecting a folder (instead of a file):
https://github.com/ookii-dialogs
For Directory Dialog to get the Directory Path, First Add reference System.Windows.Forms, and then Resolve, and then put this code in a button click.
var dialog = new FolderBrowserDialog();
dialog.ShowDialog();
folderpathTB.Text = dialog.SelectedPath;
(folderpathTB is name of TextBox where I wana put the folder path, OR u can assign it to a string variable too i.e.)
string folder = dialog.SelectedPath;
And if you wana get FileName/path, Simply do this on Button Click
FileDialog fileDialog = new OpenFileDialog();
fileDialog.ShowDialog();
folderpathTB.Text = fileDialog.FileName;
(folderpathTB is name of TextBox where I wana put the file path, OR u can assign it to a string variable too)
Note: For Folder Dialog, the System.Windows.Forms.dll must be added to the project, otherwise it wouldn't work.
I found the below code on below link... and it worked
Select folder dialog WPF
using Microsoft.WindowsAPICodePack.Dialogs;
var dlg = new CommonOpenFileDialog();
dlg.Title = "My Title";
dlg.IsFolderPicker = true;
dlg.InitialDirectory = currentDirectory;
dlg.AddToMostRecentlyUsedList = false;
dlg.AllowNonFileSystemItems = false;
dlg.DefaultDirectory = currentDirectory;
dlg.EnsureFileExists = true;
dlg.EnsurePathExists = true;
dlg.EnsureReadOnly = false;
dlg.EnsureValidNames = true;
dlg.Multiselect = false;
dlg.ShowPlacesList = true;
if (dlg.ShowDialog() == CommonFileDialogResult.Ok)
{
var folder = dlg.FileName;
// Do something with selected folder string
}
I'd suggest, to add in the nugget package:
Install-Package OpenDialog
Then the way to used it is:
Gat.Controls.OpenDialogView openDialog = new Gat.Controls.OpenDialogView();
Gat.Controls.OpenDialogViewModel vm = (Gat.Controls.OpenDialogViewModel)openDialog.DataContext;
vm.IsDirectoryChooser = true;
vm.Show();
WPFLabel.Text = vm.SelectedFilePath.ToString();
Here's the documentation:
http://opendialog.codeplex.com/documentation
Works for Files, files with filter, folders, etc
The best way to achieve what you want is to create your own wpf based control , or use a one that was made by other people
why ? because there will be a noticeable performance impact when using the winforms dialog in a wpf application (for some reason)
i recommend this project
https://opendialog.codeplex.com/
or Nuget :
PM> Install-Package OpenDialog
it's very MVVM friendly and it isn't wraping the winforms dialog
The Ookii VistaFolderBrowserDialog is the one you want.
If you only want the Folder Browser from Ooki Dialogs and nothing else then download the Source, cherry-pick the files you need for the Folder browser (hint: 7 files) and it builds fine in .NET 4.5.2. I had to add a reference to System.Drawing. Compare the references in the original project to yours.
How do you figure out which files? Open your app and Ookii in different Visual Studio instances. Add VistaFolderBrowserDialog.cs to your app and keep adding files until the build errors go away. You find the dependencies in the Ookii project - Control-Click the one you want to follow back to its source (pun intended).
Here are the files you need if you're too lazy to do that ...
NativeMethods.cs
SafeHandles.cs
VistaFolderBrowserDialog.cs
\ Interop
COMGuids.cs
ErrorHelper.cs
ShellComInterfaces.cs
ShellWrapperDefinitions.cs
Edit line 197 in VistaFolderBrowserDialog.cs unless you want to include their Resources.Resx
throw new InvalidOperationException(Properties.Resources.FolderBrowserDialogNoRootFolder);
throw new InvalidOperationException("Unable to retrieve the root folder.");
Add their copyright notice to your app as per their license.txt
The code in \Ookii.Dialogs.Wpf.Sample\MainWindow.xaml.cs line 160-169 is an example you can use but you will need to remove this, from MessageBox.Show(this, for WPF.
Works on My Machine [TM]
None of these answers worked for me (generally there was a missing reference or something along those lines)
But this quite simply did:
Using FolderBrowserDialog in WPF application
Add a reference to System.Windows.Forms and use this code:
var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
No need to track down missing packages. Or add enormous classes
This gives me a modern folder selector that also allows you to create a new folder
I'm yet to see the impact when deployed to other machines
I know this is an old question, but a simple way to do this is use the FileDialog option provided by WPF and using System.IO.Path.GetDirectory(filename).
You could use smth like this in WPF. I've created example method.
Check below.
public string getFolderPath()
{
// Create OpenFileDialog
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = false;
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (openFileDialog.ShowDialog() == true)
{
System.IO.FileInfo fInfo = new System.IO.FileInfo(openFileDialog.FileName);
return fInfo.DirectoryName;
}
return null;
}
It seems that the Microsoft.Win32 .NET library does not support selecting folders (only files), so you are out of luck in WPF (as of 7/2022). I feel the best option now is Ookii for WPF: https://github.com/ookii-dialogs/ookii-dialogs-wpf. It works great and as expected in WPF minus Microsoft support. You can get it as a NuGet package. Code behind XAML View:
public partial class ExportRegionView : UserControl
{
public ExportRegionView()
{
InitializeComponent();
}
private void SavePath(object sender, RoutedEventArgs e)
{
var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
dialog.Description = "SIPAS Export Folder";
dialog.UseDescriptionForTitle = true;
if (dialog.ShowDialog().GetValueOrDefault())
{
ExportPath.Text = dialog.SelectedPath;
}
}
}
XAML: <Button Grid.Row="1" Grid.Column="3" Style="{DynamicResource Esri_Button}" Click="SavePath" Margin="5,5,5,5">Path</Button>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Gearplay
{
/// <summary>
/// Логика взаимодействия для OpenFolderBrows.xaml
/// </summary>
public partial class OpenFolderBrows : Page
{
internal string SelectedFolderPath { get; set; }
public OpenFolderBrows()
{
InitializeComponent();
Selectedpath();
InputLogicalPathCollection();
}
internal void Selectedpath()
{
Browser.Navigate(#"C:\");
Browser.Navigated += Browser_Navigated;
}
private void Browser_Navigated(object sender, NavigationEventArgs e)
{
SelectedFolderPath = e.Uri.AbsolutePath.ToString();
//MessageBox.Show(SelectedFolderPath);
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
}
string [] testing { get; set; }
private void InputLogicalPathCollection()
{ // add Menu items for Cotrol
string[] DirectoryCollection_Path = Environment.GetLogicalDrives(); // Get Local Drives
testing = new string[DirectoryCollection_Path.Length];
//MessageBox.Show(DirectoryCollection_Path[0].ToString());
MenuItem[] menuItems = new MenuItem[DirectoryCollection_Path.Length]; // Create Empty Collection
for(int i=0;i<menuItems.Length;i++)
{
// Create collection depend how much logical drives
menuItems[i] = new MenuItem();
menuItems[i].Header = DirectoryCollection_Path[i];
menuItems[i].Name = DirectoryCollection_Path[i].Substring(0,DirectoryCollection_Path.Length-1);
DirectoryCollection.Items.Add(menuItems[i]);
menuItems[i].Click += OpenFolderBrows_Click;
testing[i]= DirectoryCollection_Path[i].Substring(0, DirectoryCollection_Path.Length - 1);
}
}
private void OpenFolderBrows_Click(object sender, RoutedEventArgs e)
{
foreach (string str in testing)
{
if (e.OriginalSource.ToString().Contains("Header:"+str)) // Navigate to Local drive
{
Browser.Navigate(str + #":\");
}
}
}
private void Goback_Click(object sender, RoutedEventArgs e)
{// Go Back
try
{
Browser.GoBack();
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Goforward_Click(object sender, RoutedEventArgs e)
{ //Go Forward
try
{
Browser.GoForward();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void FolderForSave_Click(object sender, RoutedEventArgs e)
{
// Separate Click For Go Back same As Close App With send string var to Main Window ( Main class etc.)
this.NavigationService.GoBack();
}
}
}

Resources