Disabling a button on Windows Phone Application Bar

Standard

Building an application for Windows Phone 8 using XAML allows you to create an Application Bar with buttons and menu items. To define this Application Bar you can either hand code the XAML or Build up the Application Bar through the properties explorer. Either way you end with XAML code similar to this.

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar>
            <shell:ApplicationBarIconButton 
		IconUri="/Assets/AppBar/check.png" 
		IsEnabled="True" Text="Okay"/>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

This is very simple and easy to use. The only problem with this Application Bar is that it is not bindable to Commands when you use the MVVM pattern. You can handle the tap/click events of the buttons from the Application Bar in the code behind file of your view, but this feels so against the idea of the ViewModel doing the work.

Hosted on CodePlex is the BindableApplicationBar project that was originally created for Windows Phone 7. I’ve added this library to my Windows Phone 8 project via the nuget package and it works. There is a minor issue where the error “Cannot clear the Icon while in a list” is displayed while in the XAML designed. This is not a blocking issue and does not stop your application from compiling or executing. You can gladly ignore the error.

I prefer to use the MVVM Light toolkit for binding my views and viewmodels together. Using the BindableApplicationBar binding Commands and CommandParameters to the toolbar is a simple process.

In the code of my ViewModel I created a public boolean property that is set to false when the button should be disabled in the view.

        private bool buttonEnabled;
        public bool ButtonEnaled
        {
            get { return buttonEnabled; }
            set 
            {
                buttonEnabled = value;
                RaisePropertyChanged(() => ButtonEnaled);
            }
        }

On the view side I then bind the button on the BindableApplicationBar to the ButtonIsEnabled property from the ViewModel.

     xmlns:bar="clr-namespace:BindableApplicationBar;assembly=BindableApplicationBar" 
    <bar:Bindable.ApplicationBar>
        <bar:BindableApplicationBar>
            <bar:BindableApplicationBarButton 
                Text="Calculate" 
                IconUri="/Assets/AppBar/check.png"
                Command="{Binding ButtonActionCommand}" 
		IsEnabled="{Binding ButtonEnaled, Mode=TwoWay}"/>
        </bar:BindableApplicationBar>
    </bar:Bindable.ApplicationBar>

In theory this should work. But sadly, it does not. Because the Button’s Command property is set, the Command’s CanExecute method overrides the IsEnabled flag. So setting the CanExecute value to false(Show simplistically here) should disable the button

        ButtonActionCommand.CanExecute(false);

and we can set the XAML for the button like this

    <bar:Bindable.ApplicationBar>
        <bar:BindableApplicationBar>
            <bar:BindableApplicationBarButton 
                Text="Calculate" 
                IconUri="/Assets/AppBar/check.png"
                Command="{Binding ButtonActionCommand}" 
        </bar:BindableApplicationBar>
    </bar:Bindable.ApplicationBar>

Doing this does not work either. To set the IsEnabled state of the button you have to set both the CanExecute Method and the IsEnabled property values. This might be a bug in the control. But for now it is a workaround.

        private bool buttonEnabled;
        public bool ButtonEnaled
        {
            get { return buttonEnabled; }
            set 
            {
                buttonEnabled = value;
		ButtonActionCommand.CanExecute(value);
                RaisePropertyChanged(() => ButtonEnaled);
            }
        }
    <bar:Bindable.ApplicationBar>
        <bar:BindableApplicationBar>
            <bar:BindableApplicationBarButton 
                Text="Calculate" 
                IconUri="/Assets/AppBar/check.png"
                Command="{Binding ButtonActionCommand}" 
		IsEnabled="{Binding ButtonEnaled, Mode=TwoWay}"/>
        </bar:BindableApplicationBar>
    </bar:Bindable.ApplicationBar>

After some trial and error I finally managed to enable and disable buttons on the application bar as and when I need to. Happy days.

A SQL Query I find useful

Standard

While working on an Accounting Software package some years ago, where we have multiple companies in a single database with GUID’s as primary keys in some 100 tables I needed to find a specific GUID somewhere in the database.

Now, I have not written this this query, and for the life of me, I can not remember where I got it. I am posting it here because I found it immensely useful.

DECLARE @SearchStr nvarchar(100)

set @SearchStr = 'What you want to find'

CREATE TABLE #Results 
(

     ColumnName nvarchar(370),

     ColumnValue nvarchar(3630)

)

SET NOCOUNT ON

DECLARE @TableName nvarchar(256)

DECLARE @ColumnName nvarchar(128)

DECLARE @SearchStr2 nvarchar(110)

SET @TableName = ''

SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

WHILE @TableName IS NOT NULL

     BEGIN

          SET @ColumnName = ''

          SET @TableName =

          (

               SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))

               FROM INFORMATION_SCHEMA.TABLES

               WHERE TABLE_TYPE = 'BASE TABLE'

               AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)&gt;@TableName

               AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) +     '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
          )

     WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)     
     BEGIN

     SET @ColumnName =

     (

     SELECT MIN(QUOTENAME(COLUMN_NAME))         
     FROM INFORMATION_SCHEMA.COLUMNS        
     WHERE TABLE_SCHEMA = PARSENAME(@TableName, 2)         
     AND TABLE_NAME = PARSENAME(@TableName, 1)
     AND DATA_TYPE IN ('char','varchar','nchar','nvarchar','uniqueidentifier','decimal','int')
     AND QUOTENAME(COLUMN_NAME)&gt;@ColumnName)

     IF @ColumnName IS NOT NULL
          BEGIN

               INSERT INTO #Results

               EXEC ('SELECT ''' + @TableName + '.' + @ColumnName + ''', 
               LEFT('+@ColumnName+',3630) 
               FROM ' + @TableName + ' (NOLOCK) '+' 
               WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2        
          )

          END

     END

END

SELECT ColumnName, ColumnValue FROM #Results

DROP TABLE #Results

Dynamic CRM Connection

Standard

A while ago I had to build a piece of software that connects to Dynamic CRM and retrieve values from an Entity to Export it to CSV file. Reading through existing code of other developers I noticed a lot of Impersonation taking place, or credentials being stored in the web.config/app.config file. I do not like this. I want my application to connect to CRM using my Active Directory credentials.

CRM is still a great big playpen to me where I feel and push the boundaries to see what it can do with it. Lacking experience with it allows me a lot of freedom to experiment.

After playing a bit and reading a lot on how to best avoid the whole credentials-in-the-config-file scenario, I came up with these classes.

This class build up an Organization Service Url for your favourite CRM Organization

using System;
using System.Configuration;

namespace MyApplication.CrmServices
{
    internal class OrganizationServiceUrl
    {
        const string XrmServiceLocation = @"/XRMServices/2011/Organization.svc";

        public OrganizationServiceUrl(string organizationUrl = null)
        {
            if (string.IsNullOrWhiteSpace(organizationUrl) && string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["CrmInstanceUrl"]))
                throw new InvalidOperationException("Organization URL is required.");

             organizationUrl = string.IsNullOrWhiteSpace(organizationUrl) ? ConfigurationManager.AppSettings["CrmInstanceUrl"] : organizationUrl ;
            if (string.IsNullOrWhiteSpace(organizationUrl))
                throw new InvalidOperationException(@"The [URL] setting was not found in the <appSettings> section of the configuration file.");

            Uri = new Uri(string.Format("{0}{1}",
                organizationUrl.EndsWith("/") ? organizationUrl.Substring(0, organizationUrl.LastIndexOf("/") - 1) : organizationUrl,
                XrmServiceLocation));
        }
        public Uri Uri { get; private set; }
    }
}

Next up I created a class that will give me ClientCredentials from the Default NeworkCredentials and accepts the OrganizationServiceUrl as a parameter.

using System.ServiceModel.Description;
using System.Net;

namespace MyApplication.CrmServices
{
    internal class CrmClientCredentials : ClientCredentials
    {
        private readonly OrganizationServiceUrl serviceUrl;
        public CrmClientCredentials(OrganizationServiceUrl serviceUrl)
            : base()
        {
            this.serviceUrl = serviceUrl;
            this.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials.GetCredential(serviceUrl.Uri, "Basic");
        }
    }
}

Finally, I can connect to the Organization service through the CRM SDK without having to store any credential in the config file.

using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;

namespace MyApplication.CrmServices
{
    public class Connector : IDisposable
    {
        private OrganizationServiceUrl organizationServiceUrl;
        private CrmClientCredentials crmClientCredentials;
        public bool disposed;

        public Connector()
        {
            organizationServiceUrl = new OrganizationServiceUrl(string.Empty);
            crmClientCredentials = new CrmClientCredentials(organizationServiceUrl);
            disposed = false;
        }

        public Connector(string organizationUrl)
        {
            organizationServiceUrl = new OrganizationServiceUrl(organizationUrl);
            crmClientCredentials = new CrmClientCredentials(organizationServiceUrl);
            disposed = false;
        }

        public IOrganizationService Proxy
        {
            get { return new OrganizationServiceProxy(organizationServiceUrl.Uri, null, crmClientCredentials, null); }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (organizationServiceUrl != null)
                        organizationServiceUrl = null;
                    if (crmClientCredentials != null)
                        crmClientCredentials = null;
                }
                disposed = true;
            }
        }
    }
}

Whether this is the correct, or even acceptable, way of connecting to CRM I do not know. What I do know, is that thus far, it works for me. It is simple and reusable.

Saving Window position

Standard

When I use an application and I move the window to a new location on my monitor, or even move it over to the second monitor I expect that it would start up where I left it last. Very few application, to my annoyance, does this.

To build this into you applications is such an easy thing to do.

Bind you Location property to in the property binding window.

In the properties toolbox of your solution set a name for Location property.

Property Binding Dialog

This property will be stored in your app.config file.

 <userSettings>
    <xxx.UI.Properties.Settings>
      <setting name="ExportFolder" serializeAs="String">
        <value>Choose a folder...</value>
      </setting>
      <setting name="StartupPosition" serializeAs="String">
        <value>0, 0</value>
      </setting>
    </xxx.UI.Properties.Settings>
  </userSettings>

Next add code to you Window’s ResizeEnd event. This event is called once you stop moving a window too.

        private void MainWindow_ResizeEnd(object sender, EventArgs e)
        {
            Properties.Settings.Default.StartupPosition = Location;
        }

Now, in the constructor add the following event subscription.

// Save settings
Properties.Settings.Default.PropertyChanged += (o, e) => Properties.Settings.Default.Save();

Next time your window start’s up it will be in the location the user left it, even on the second monitor if it was last left there.