Search code examples
c#.netwpfwpf-controls

C# WPF - Passing IConfiguration to Page's ViewModel from Window


I can easily pass in an IConfiguration appsettings.json to a Window in WPF, which is what I have done in the past. Now I am trying to do this the proper way and pass it into a ViewModel that is assigned as the DataContext of a Page that is being displayed on a Window. I'm loading the Page into a Frame on the Window. I would like to pass the config to the ViewModel of the Page so I dont have to reread it in manually.

Here is what I currently have and some stuff I tried:

    public partial class HomeWindow : Window
    {
        readonly IConfiguration _config;
        
        public HomeWindow(IConfiguration config)
        {
            _config = config;

            // Instantiate the Object with JSON settings.
            InitializeComponent();
            DataContext = new HomeWindowVM(config)
        } 
    }


    public class HomeWindowVM
    {
        readonly IConfiguration _config;
        //public INotify btnCheckoutPage { get; set; }
        public object MyFrameContent { get; set; }

        public HomeWindowVM(IConfiguration config)
        {
            _config = config;
            CheckoutClickCommand = new MyCommand(CheckoutClick);
            ShipmentClickCommand = new MyCommand(ShipmentClick);
            frameURI = new INotify();
            frameVis = new INotify();
            frameVis.MyProperty = "Hidden";
        }

        private void CheckoutClick()
        {
            frameURI.MyProperty = "CheckoutPage.xaml";
            frameVis.MyProperty = "Visible";
// I tried this 
            //CheckoutPage checkoutPage = new CheckoutPage(_config);
            //MyFrameContent = new CheckoutPage(_config);

        }
    }


    public partial class CheckoutPage : Page
    {
        readonly IConfiguration _config;

        public CheckoutPage()
        {
            InitializeComponent();
            DataContext = new CheckoutPageVM();
        }
        public CheckoutPage(IConfiguration config)
        {
            _config = config;
            InitializeComponent();

            //Frame frame = new Frame();
            //MainView 
            DataContext = new CheckoutPageVM(config);
        }
    }


    public class CheckoutPageVM 
    {
        readonly IConfiguration _config;

        public CheckoutPageVM(IConfiguration config)
        {
            _config = config;
            LblErrorProjectNum = new INotify();
            LblErrorProjectNum.MyProperty = "Hidden";
            LblErrorTransfer = new INotify();
            LblErrorTransfer.MyProperty = "Hidden";
            CheckoutSubmitCommand = new MyCommand(CheckoutSubmit);            
        }

Solution

  • There's no one proper way to do this, but I'm guessing you've got a background in ASP.NET and are familiar with dependency injection. Of course WPF doesn't use that pattern and it's probably overkill in this case. A statically accessible singleton works perfectly fine and avoids the morass of passing the config instance around through constructors or other over-engineered solutions:

    // In your Model layer
    public static class MyConfiguration
    {
         public static IConfiguration Instance { get; private set; }
    
         public static void Load(IConfiguration config) 
         {
              // call this when the app initializes
              Instance = config;
         }
    }
    

    Then if individual classes need instance properties for binding, etc., it's as simple as:

    public partial class HomeWindow : Window
    {
        public IConfiguration Config => MyConfiguration.Instance;
        // ...
    }
    
    public class CheckoutPageVM 
    {
        public IConfiguration Config => MyConfiguration.Instance;
        // ...
    }
    
    public partial class CheckoutPage : Page
    {
        public IConfiguration Config => MyConfiguration.Instance;
        // ...
    }
    

    etc.