Persistable View Models & XAML for Config
I’m working on a XamlPad application sample using WPF4. As part of that, I’m ending up exploring ideas around persistable view models, which may end up having a lot to do with Xaml for Config.
Here is the current persisted view model for my application, which you may be able to guess can open several files at one time. I happen to display them with a tabcontrol. When you close the application, it saves the window location, all the documents I had open, what mode I was viewing them in, and the position of the splitter for each.
Here is the config.xaml file for this application:
- <XamlPadConfig ActiveXamlDocument="1" WindowHeight="640" WindowLeft="1692" WindowTop="169" WindowWidth="837" xmlns="clr-namespace:XamlPadHelpers;assembly=XamlPadHelpers">
- <XamlDocumentViewModel BottomRowHeight="1027*" TopRowHeight="116*">
- <XamlDocument FileName="C:\Users\rrelyea\AppData\Local\Temp\temp.xaml" />
- </XamlDocumentViewModel>
- <XamlDocumentViewModel BottomRowHeight="330*" TopRowHeight="237*" XamlViewState="Xaml">
- <XamlDocument FileName="C:\Users\rrelyea\AppData\Local\Temp\temp2.xaml" />
- </XamlDocumentViewModel>
- <XamlDocumentViewModel BottomRowHeight="344*" TopRowHeight="223*" XamlViewState="View">
- <XamlDocument FileName="C:\Users\rrelyea\Documents\doc.xaml" />
- </XamlDocumentViewModel>
- <XamlDocumentViewModel BottomRowHeight="*" TopRowHeight="2*">
- <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\XamlDesigner\XamlDesigner\ProjectExplorer.xaml" />
- </XamlDocumentViewModel>
- </XamlPadConfig>
Here is my mainwindow ctor(). It loads the config file before loading MainWindow.xaml (which has bindings to config data):
- public MainWindow()
- {
- xamlPadConfig = GetConfigData();
- DataContext = xamlPadConfig;
- InitializeComponent();
- this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
- }
Here is a routine that loads the config file or provides a set of defaults. (these defaults could be specified as a separate XAML file that I embed in the .exe if I wanted.)
- private XamlPadConfig GetConfigData()
- {
- XamlPadConfig configData = null;
- configFile = System.Environment.CurrentDirectory + "\\config.xaml";
- if (File.Exists(configFile))
- {
- try
- {
- configData = (XamlPadConfig)XamlServices.Load(configFile);
- }
- catch (Exception)
- {
- //problem with settings file, ignore it, eventually replace it
- }
- }
- if (configData == null)
- {
- configData = new XamlPadConfig()
- {
- WindowHeight = 400,
- WindowWidth = 600,
- XamlDocumentViewModels = {
- CreateDefaultXamlDocumentViewModel(Environment.GetEnvironmentVariable("temp") + "\\temp.xaml")
- }
- };
- }
- return configData;
- }
Here is a routine which creates a new XamlDocumentViewModel given a file location. For new files with no location yet, I end up passing in null.
- private static XamlDocumentViewModel CreateDefaultXamlDocumentViewModel(string fileName)
- {
- return new XamlDocumentViewModel()
- {
- XamlViewState = XamlPadHelpers.XamlViewState.Split,
- XamlDocument = new XamlDocument()
- {
- FileName = fileName,
- },
- TopRowHeight = new GridLength(2, GridUnitType.Star),
- BottomRowHeight = new GridLength(1, GridUnitType.Star)
- };
- }
Here is a routine which runs when the window is closed and saves that config.
- void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
- {
- XamlServices.Save(configFile, xamlPadConfig);
- }
Here is my current MainWindow.xaml:
- <Window x:Class="XamlPadSample.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:xph="clr-namespace:XamlPadHelpers;assembly=XamlPadHelpers"
- Title="XamlPad Sample"
- Height="{Binding WindowHeight, Mode=TwoWay}"
- Width="{Binding WindowWidth, Mode=TwoWay}"
- Top="{Binding WindowTop, Mode=TwoWay}"
- Left="{Binding WindowLeft, Mode=TwoWay}"
- >
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="20" />
- <ColumnDefinition Width="*" />
- </Grid.ColumnDefinitions>
- <StackPanel Orientation="Horizontal" Grid.Column="0">
- <StackPanel.LayoutTransform>
- <RotateTransform Angle="90" />
- </StackPanel.LayoutTransform>
- <Button Click="New">New</Button>
- <Button Click="Open">Open</Button>
- <Button Click="Save">Save</Button>
- <Button>Exit</Button>
- </StackPanel>
- <TabControl ItemsSource="{Binding XamlDocumentViewModels}"
- SelectedIndex="{Binding ActiveXamlDocument}" Name="documentsTabControl"
- Grid.Column="1"
- >
- <TabControl.ItemTemplate>
- <DataTemplate DataType="{x:Type xph:XamlDocumentViewModel}">
- <StackPanel Orientation="Horizontal">
- <StackPanel.ToolTip>
- <TextBlock Text="{Binding XamlDocument.FileName}" />
- </StackPanel.ToolTip>
- <TextBlock Text="{Binding XamlDocument.FileNameShort}"/>
- <TextBlock Text="{Binding XamlDocument.DirtyString}" />
- </StackPanel>
- </DataTemplate>
- </TabControl.ItemTemplate>
- <TabControl.ContentTemplate>
- <DataTemplate DataType="{x:Type xph:XamlDocumentViewModel}" >
- <xph:XamlPad x:Name="xamlPad" />
- </DataTemplate>
- </TabControl.ContentTemplate>
- </TabControl>
- </Grid>
- </Window>
I’ll likely post this complete example soon. This was fun to build and sends my mind in several directions on possibilities.
I’m curious how many of you are trying to save and load your view models?