How to display icons in Appbar’s secondary menu

By default the secondary menu from an AppBar does not display a icon. However, it’s pretty trivial to change.

<Page.BottomAppBar>
   <CommandBar>
      <AppBarButton Label="A" Icon="Accept" >
         <CommandBar.SecondaryCommands>
           <AppBarButton Label="B" Icon="Accept" Style="{StaticResource AppBarButtonStyle1}" />
         </CommandBar.SecondaryCommands>
   </CommandBar>
</Page.BottomAppBar>

Then in the AppBarButtonStyle1 change the overflow, here is very quick hack to prove the point;

 <VisualState x:Name="Overflow"
  <Storyboard>
     <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ContentRoot">
        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
     </ObjectAnimationUsingKeyFrames>
     <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="OverflowTextLabel">
        <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
     </ObjectAnimationUsingKeyFrames>
  </Storyboard>
 </VisualState>

and that gives you

secondary

Obviously that is ugly but it is the base of how to provide the icons

How to debug Continuum?

Developing for Continuum poses an initially thorny question, “my phone is plugged into the dock, how can I also plug it into my PC to debug?”. My recommendation is to get yourself a Miracast device and use Continuum’s wireless connection feature. That way your phone can be plugged into your PC for debugging while casting a Continuum desktop to your monitor. If you really need a keyboard and mouse then they’ll have to be wireless too, but the phone’s virtual trackpad and keyboard are enough to get by.

Should I buy into Continuum?

The upcoming release of Windows 10 Mobile promises the innovation of Continuum.  The idea is simple. With a device, such as the Lumia 950, you have the power of a PC in a tiny package so why not use it as a desktop PC? With a mobile dock (or wireless options) you can plug your tiny PC into a proper screen, keyboard and mouse and carry on with your usual desktop tasks. But should I buy into this?

Can a mobile device replace a desktop setup?

The problem in answering this question is that you first need to ask, “what do I use a desktop for”?

I’m not happy with these categories of users but here we go.

The high-end user;

My own setup is not that far from the Continuum scenario. I have a laptop as my main device and when I want to really settle down and do some work I ‘dock’ that to a monitor, keyboard and mouse. The difference is that my laptop has a much higher spec than a mobile phone (yes it will include tablets, but oh you know we’re talking about phones, let’s call it a phone). I need that spec because I develop software which is a pretty intense task for a computer. It could be some time before these tiny PC phones will be able to go toe-to-toe with a mid-high spec laptop. There will be a certain percentage of PC users that will fall into this category; Photoshop users, Video editing, CAD/CAM, PC gamers, etc. For these users the current Continuum offering probably isn’t going to tempt them away.

The non-pro user;

People that use computers as part of their everyday life. They browser the web, write a Word document, do a bit of accounting in Excel, Skype a friend, watch a bit of Netflix, view their holiday photos, post on Facebook, a bit of casual gaming, etc. These activities are all well within the capabilities of the tiny PC. Many of those activities would be enhanced by a desktop.

The business user;

I’m thinking about the person who needs to read and write Office documents, create presentations, work on large Excel spreadsheets, etc. To continue the stereo type further; probably do a bit of work on a crowded train, ‘project’ their PowerPoint presentation on a large screen, turn up to their usual office desk and start editing that large spreadsheet. These tasks also fall into the tiny PC catchment.

Can a mobile device replace a laptop?

The traditional desktop has seen a large decline over the years with customers turning to laptops and tablets. Continuum is aimed at mobile devices, including tablets, so if the user only has a tablet then everything is good. The main adversary of Mobile Continuum is the laptop. The laptop is really just a compacted version of the desktop setup, you get an ok monitor, you get an ok keyboard and you might even be lucky enough to get a decent trackpad. We trade this mediocre experience for convenience.  You can throw this compact desktop in your bag, and unfold it almost anywhere. The problem with mobile devices is that mediocre experience is traded for a pretty poor experience in order to gain reduced weight and size.  But if we’re honest, using a tablet without additional accessories to turn it into back into a low-end laptop is a poor experience. Hence the need for Continuum. But, I’m now using my Laptop on a train, in a café, on my sofa. I’m not going to pull out a Mobile doc, a keyboard and a 28” monitor from my trendy messenger bag and juggle them on my lap. So it’s not really aimed at these users, it is about those category of users who need to spend some time carrying out their tasks in their comfortable desktop environment.

Working from Phone, continuing on Desktop

One of the big selling points for modern applications is the number of platforms an application can be used on. Typically your document (photo, spreadsheet, etc.) can be started on one device, stored in the Cloud and then completed on another. In other words you could write a large Word document in the comfort of a desktop, make a few notes on your phone whilst on the train and then finish and send off the amendments from a café. The difficulty for Continuum here is that for many of our categories, even if they do not have a laptop, they will be able to access a real desktop. They can sit at their (home) office desk and carry on with the document they were making notes about on their phone. If the user is concerned that they will not be able to continue on the document at their next destination then will carrying a mobile doc, keyboard and mouse be a viable alternative to a laptop?

Continuum vs. Casting

Previously I highlighted areas where Continuum could be used to show presentations or stream Netflix. In these examples you could also use Continuum in conjunction with a Miracast dongle. However, that is very close to current Casting offerings. Some phone and TV combinations will provide this without any additional equipment.

Should I buy into Continuum?

On paper it would seem that Continuum is great if you fall into a niche category, but for the majority of the cases it doesn’t really seem to achieve many of the common requirements you would expect from a humble laptop or desktop. However, there are a couple of aspects that I’ve yet to cover. The first is budget. Let’s assume you are sitting at home with a 5 year old desktop that is on its last legs and really needs to be replaced. You’ve got a feature phone that frankly you’re a little embarrassed about. You’ve got $500 to spend, how to you divide your budget? You could spend $500 on a phone and be stuck with a really poor desktop experience. You could spend $500 on a laptop or desktop but you’ll still be stuck be your barely-capable-of-running-Java phone. Or perhaps you’d like to spend $500 on a high end phone and plug it into your existing desktop setup – yes?

Secondly this is Continuum version 1. I’m sure we can expect to see more features arriving for Continuum. Maybe you do not see a key feature now, but it might be just around the corner.

I started this post because I am hovering over the ‘buy with dock’ button. Fortunately at this point in time I can justify the purchase of a new phone without precluding a separate laptop. So having written out the rationale for Continuum and realising that it probably is not really useful to me, I still find myself hovering over that button. Sometimes shiny new things are just appealing.

Element to support changing focus in MVVM

The other day I moaned that setting focus to a control in an MVVM environment felt like a painful disconnect. There are probably a dozen ways to resolve this issue, but I thought I’d try to use a method that at least isn’t a Behaviour.

Consider the following snippet of XAML

   <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <local:FocusManagerElement ControlName="{Binding SuggestedFocusName}" />
        <StackPanel>
            <TextBox x:Name="Barny" />
            <TextBox x:Name="Fred" />
            <TextBox x:Name="Bert" />
            <Button Content="Test" Tapped="Button_Tapped" />
        </StackPanel>
    </Grid>

The idea is that the FocusManagerElement is bound to the current view model and will set focus to whatever control is named by the View Model via the SuggestedFocusName property. When the logic in the View Model changes and we want to change the focus the we can simply update that property.

    public class TestViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string suggestedFocusName;
        public string SuggestedFocusName
        {
            get { return this.suggestedFocusName; }

            set
            {
                if (this.suggestedFocusName != value)
                {
                    this.suggestedFocusName = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("SuggestedFocusName"));
                    }
                }
            }
        }

        public void DoWork()
        {
            // do some logic that means we need to change the focus
            this.SuggestedFocusName = "Fred";
        }
    }

From a developers point of view I think that’s pretty easy and flexible to use. All that remains is to show the implementation of the Focus Manager Element itself;

namespace AppFocusManager
{
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;

    /// <summary>
    /// Element to support setting the focus via a bindable object
    /// </summary>
    public class FocusManagerElement : FrameworkElement
    {
        // Using a DependencyProperty as the backing store for ControlName. 
        public static readonly DependencyProperty ControlNameProperty =
            DependencyProperty.Register("ControlName", typeof(string), typeof(FocusManagerElement), new PropertyMetadata(null, new PropertyChangedCallback(ControlNamePropertyChanged)));

        /// <summary>
        /// Name of control to set focus to
        /// </summary>
        public string ControlName
        {
            get { return (string)GetValue(ControlNameProperty); }
            set { SetValue(ControlNameProperty, value); }
        }

        /// <summary>
        /// Control Name has changed
        /// </summary>
        /// <param name="dependencyObject">the instance of FocusManagerElement</param>
        /// <param name="eventArgs">new name of control to set focus to</param>
        private static void ControlNamePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            var focusManagerElement = dependencyObject as FocusManagerElement;
            var controlName = eventArgs.NewValue as string;
            if (!string.IsNullOrEmpty(controlName))
            {
                var elementToFocusOn = focusManagerElement.FindName(controlName) as Control;
                if (elementToFocusOn != null)
                {
                    elementToFocusOn.Focus(FocusState.Programmatic);
                }
            }
        }
    }
}

Read and Edit OpenXml Docs (Word, Excel, etc.) in Windows 10 with c#

It is often useful to be able examine and edit Microsoft Office Documents in your own applications. Office Documents have being using the OpenXml format for some time now, in this post I’ll demonstrate how you can read and manipulate the data.

NB For more information, and to download some great tools including the Open , visit http://openxmldeveloper.org/

 

Reading data from Excel

NB For some reason you CANNOT use any other code to read a document if the document is already open in an Office Product, in this case Excel. If you get AccessDenied then check the document isn’t already open.

Consider the following spread-sheet;

image

I’ve saved this document as Book1.xlsx. If you haven’t downloaded the Open XML SDK 2.5 for Microsoft Office tools then rename the document to Book1.zip and open the Zip. I am not going to go into great depth about how the document packaging works, see the open xml developer site for more information. But basically each document is a Zip file containing a content catalogue and folders with the data represented in the document. So to examine the data in the first sheet you will find that located at; xl/worksheets/sheet1.xml

The first step is to open the document;

            FileOpenPicker opener = new FileOpenPicker();
            opener.ViewMode = PickerViewMode.Thumbnail;            
            opener.FileTypeFilter.Add(".xlsx");

            
            StorageFile file = await opener.PickSingleFileAsync();
            if (file != null)
            {
                XmlDocument worksheet = null;
                using (var fileStream = await file.OpenReadAsync())
                {
                    using (ZipArchive archive = new ZipArchive(fileStream.AsStream(), ZipArchiveMode.Read))
                    {
                        worksheet = this.GetSheet(archive, "sheet1");
                    }
                }
            }

You can see that we’ve opened the document as a Zip Archive, now we can read the specific sheet file held within, in this case I’m storing the result in an XmlDocument, this is just my choice of Xml parser;

        private XmlDocument GetSheet(ZipArchive archive, string sheetName)
        {
            XmlDocument sheet = new XmlDocument();
            ZipArchiveEntry archiveEntry = archive.GetEntry("xl/worksheets/" + sheetName + ".xml");

            using (var archiveEntryStream = archiveEntry.Open())
            {
                using (StreamReader reader = new StreamReader(archiveEntryStream))
                {
                    string xml = reader.ReadToEnd();
                    sheet.LoadXml(xml);
                }
            }

            return sheet;
        }

Now we have the document, we can grab a value, here via XPath

       private string ReadCell(XmlDocument worksheet, string cellAddress)
        {
            string value = string.Empty;           
            XmlElement row = worksheet.SelectSingleNodeNS("//x:c[@r='" + cellAddress + "']", "xmlns:x=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"") as XmlElement;
            if (row != null)
            {
                value = row.InnerText;
            }
            
            return value;
        }

There you have it, you’ve read the data in cell B2.

Writing data in Excel

Let’s now change that value from 2 to 99.

using (var fileStream = await file.OpenStreamForWriteAsync())
                {
                    using (ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update))
                    {
                        await WriteCell(archive, worksheet, "sheet1", "B2", "99");
                    }
                }

In this example I’ve chosen to simply remove the sheet from the archive and put a new version back.

        private async Task WriteCell(ZipArchive archive, XmlDocument worksheet, string sheetName, string cellAddress, string value)
        {            
            XmlElement row = worksheet.SelectSingleNodeNS("//x:c[@r='" + cellAddress + "']/x:v", "xmlns:x=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"") as XmlElement;
            if (row != null)
            {
                row.InnerText = value;
            }

            string sheetFilename = "xl/worksheets/" + sheetName + ".xml";
            ZipArchiveEntry archiveEntry = archive.GetEntry(sheetFilename);
            archiveEntry.Delete();

            archiveEntry = archive.CreateEntry(sheetFilename);
            using (var archiveEntryStream = archiveEntry.Open())
            {
                using (DataWriter writer = new DataWriter(archiveEntryStream.AsOutputStream()))
                {
                    writer.WriteString(worksheet.GetXml());

                    await writer.StoreAsync();
                    await writer.FlushAsync();
                    writer.DetachStream();
                }               
            }
        }

Let’s open the file in Excel and check our result;

 

image

Looks good.

 

What else can you do?

We’ve seen a simple example of reading and writing to Excel. But these basic techniques allow you to do pretty much anything with any Office document. The underlying schema was developed to aid the use of tools, so anything is possible. Again I would point to Open XML SDK 2.5 for Microsoft Office and http://openxmldeveloper.org/ for information about how to interpret the various document types. My recommendation is to write an example document and use the SDK tools to learn how to reproduce it.