Thursday, May 2, 2013

Using X509Certificate2UI.SelectFromCollection() with WPF and MVVM

I had a task which involves making the user select a certificate from the store.
(We are using .NET)

I used WPF and the MVVM pattern for the UI; and I used the MVVM Light Toolkit to help with MVVM development.

I used the X509Certificate2UI.SelectFromCollection() method to show a dialog for the user to select a certificate (X509Certificate2UI is in the System.Security.Cryptography.X509Certificates namespace, System.Security.dll assembly)
X509CertificateCollection certificateCollection = X509Certificate2UI.SelectFromCollection(
                    store.Certificates, "Caption", "Message",
                    X509SelectionFlag.SingleSelection);


My problem was the dialog that X509Certificate2UI.SelectFromCollection() is not modal and it does not close when I close the main window.

The solution was to use the overloaded method of X509Certificate2UI.SelectFromCollection() which accepts a handle to the parent window.
WindowInteropHelper windowHwnd =new WindowInteropHelper(this); 
IntPtr hWnd = windowHwnd.Handle;
X509CertificateCollection certificateCollection = X509Certificate2UI.SelectFromCollection(
                    store.Certificates, "Caption", "Message",
                    X509SelectionFlag.SingleSelection, hWnd);

[To know more about Win32 Handles go to "Win32 Handle (HWND) & WPF Objects - A Note" - http://www.abhisheksur.com/2010/12/win32-handle-hwnd-wpf-objects-note.html ...]

But there was another problem: Because I was using MVVM with WPF I have to put this logic inside my ViewModel. But ViewModel does not have direct acces to the Window element!

The solution was to pass the Window object as parameter to a Command object as shown below

[The View - XAML]

<Window ...  Name="TheMainWindow"
   DataContext="{Binding Main, Source={StaticResource Locator}}">
  <Button Command="{Binding SelectCertificateCommand}" CommandParameter="{Binding ElementName=TheMainWindow}" Content="Select Certificate From the Store" />
 </Window>

[The ViewModel]
[ViewModelBase and RelayCommand are from the MVVM Light Toolkit]
    public class MainViewModel : ViewModelBase
    {
        private X509Certificate2 _selectedCertificate;

        public ICommand SelectCertificateCommand { get; private set; }

        public MainViewModel()
        {
            this.SelectCertificateCommand = new RelayCommand(
                (window) =>
                {
                    X509Certificate2 cert = PickCertificate(StoreLocation.CurrentUser, StoreName.My, window);
                    if (cert != null)
                    {
                        this.Certificate = cert;
                    }
                });
        }

        public X509Certificate2 Certificate
        {
            get { return _selectedCertificate; }
            set
            {
                if (_selectedCertificate == value) { return; }
                _selectedCertificate = value;
                RaisePropertyChanged(() => Certificate);
            }
        }

        private static X509Certificate2 PickCertificate(StoreLocation location, StoreName name, Window window)
        {
            X509Store store = new X509Store(name, location);
            try
            {
                store.Open(OpenFlags.ReadOnly);

                // pick a certificate from the store 
                X509Certificate2 certificate = null;
                X509CertificateCollection certificateCollection = X509Certificate2UI.SelectFromCollection(
                    store.Certificates, "Select a certificate", "Select a certificate",
                    X509SelectionFlag.SingleSelection, new WindowInteropHelper(window).Handle);
                if (certificateCollection.Count > 0)
                {
                    certificate = (X509Certificate2)certificateCollection[0];
                }

                return certificate;
            }
            finally
            {
                store.Close();
            }
        }
    }





  
Free Lessons for Chruch Pianists:
Free lessons, tips and downloads for church pianists

DVD Courses (Reharmonization, Play by Ear!, Arranging, Accompanying, Theory for Church Pianists, etc.):
Over 30 hours of DVD instruction for church pianists