Monday, May 20, 2013

Implementing MVVM for the Silverlight Autocomplete Box

This is the continuation post of my previous MVVM post. Here I am explaining on how to use Silverlight AutoCompleteBox. This is the XAML file content. 

<sdk:AutoCompleteBox x:Name="autoCompleteBoxFarm" ItemsSource="{Binding SomeNumbers}"
HorizontalAlignment="Left"  Grid.Row="2" Grid.Column="1" Width="110" Height="20"
MinimumPopulateDelay="500" Text="{Binding KeywordSearchText, Mode=TwoWay}" >
<i:Interaction.Behaviors>
<viewModels:ImmediateUpdateBehavior></viewModels:ImmediateUpdateBehavior>
</i:Interaction.Behaviors>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding KeywordSearchFilterCommand}" CommandParameter="{Binding autoCompleteBoxFarm}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</sdk:AutoCompleteBox>

The autocompleteBox "Text" property is bound with the class property "KeywordSearchText". Please note this is a two way binding.

We need an event trigger. Hence we are using the "TextChanged" event as an trigger. Whenever the text is changed, we are invoking a command called "KeywordSearchFilterCommand". If required we can even pass the complete 'autoCompleteBox' as parameter but this is not required.

Here is the "SomeNumbers" property.

private ICollectionView someNumbers;
public ICollectionView SomeNumbers
        {
            get
            {
                return someNumbers;
            }
            set
            {
                someNumbers = value;
                RaisePropertyChanged("SomeNumbers");
            }
        }

Here is the "KeywordSearchText" property.

private string keywordSearchText;
public string KeywordSearchText
        {
            get { return keywordSearchText; }
            set
            {
                keywordSearchText = value;
                RaisePropertyChanged("KeywordSearchText");
            }
        }

 
Here is the "KeywordSearchFilterCommand" property.


private RelayCommand<object> keywordSearchFilterCommand;
public ICommand KeywordSearchFilterCommand
        {
            get
            {
                return keywordSearchFilterCommand;
            }
        }
 

Make sure to initialize the command during the ViewModel constructor.


private void PrepareCommands()
        {
keywordSearchFilterCommand = new RelayCommand<object>(PerformKeywordSearch, CanPerformKeywordSearch);
    }

The function "CanPerformKeywordSearch" is always returning true. Other logic can be implemented here. The function "PerformKeywordSearch" is used to get all the "SomeNumbers"  and this can be an asynchronous call.



public bool CanPerformKeywordSearch(object obj)
        {
        return true;
    }

   public void PerformKeywordSearch(object obj)
        {
theModel.GetAllSomeNumbers(StateCodes.CurrentItem.ToString(), CountyCodes.CurrentItem.ToString(), KeywordSearchText);
        }

The asynchronous call will return back. Once the results are obtained, it can be used to populate the SomeNumbers property. 

List<string> availableSomeNumbers = genAsyncDataResults.asyncDataResults as List<string>;
SomeNumbers = new PagedCollectionView(availableSomeNumbers);

Once "SomeNumbers" value is assigned, it will show-up in the "autocompleteBox".

Hope this code helps to implement MVVM when using "autocompleteBox".

Cheers
Anand 
  
 
  
 
 



 

Saturday, April 27, 2013

MVVM Design Pattern in Silverlight


MVVM in Silverlight is an interesting concept. Please read few articles related to MVVM before implementing the techniques described here.

After reading several contents related to MVVM in Silverlight, I came to the following conclusions.
1. MVVM allows the View (UI) to be separated from the Data and the Logic.
2. MVVM implementation will completely remove all the code in the code-behind xaml.cs file.
Here are some implementation techniques.

Let’s assume that the UI contains a dropdown list. This list needs to be populated and whenever the user makes a selection the application needs to know what the user has selected.

Here is the XAML code.

<ComboBox x:Name="comboBoxStateCode" ItemsSource="{Binding StateCodes}"   Grid.Row="0" Grid.Column="1"  HorizontalAlignment="Left" Width="110" Height="20" />
The ItemsSource is bound with the property "StateCodes". This "StateCodes" property belongs to the View Model class. It is declared like this in the View Model

Here is the code in the .cs file of the View Model.

     private ICollectionView stateCodes;
        public ICollectionView StateCodes
        {
            get
            {
                return stateCodes;
            }
            set
            {
                stateCodes = value;
                RaisePropertyChanged("StateCodes");
            }
        }

Here we are using "ICollectionView" and we are also raising the "Property Changed Event". There is a reason behind these two.


 List<string> availablestateCodes = someFunctiontogetData() as List<string>;
 StateCodes = new PagedCollectionView(availablestateCodes);
 stateCodes.CurrentChanged +=new EventHandler(stateCodes_CurrentChanged);

Reason 1.

This helps to trigger an event whenever the user makes a selection from the dropdown list.

stateCodes.CurrentChanged - This is an Event Handler.

void stateCodes_CurrentChanged(object sender, EventArgs e)
{
string userSelectedStateCode = stateCodes.CurrentItem as string;
UserMessage = "User selected State : " + userSelectedStateCode ;
}

Reason 2.

The following call makes sure that the property (remember the public property not the private variable) changed event call is triggered. This trigger ensures that whenever the property value is changed the values are reflected back in the UI.


RaisePropertyChanged("StateCodes");

Make sure that the View Model class is derived from INotifyPropertyChanged

public class myVMClass : INotifyPropertyChanged

Here is the Property Changed Event.

public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyname)
      {
            if (PropertyChanged != null)
            {
   PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }

Also make sure the XAML file has been linked to the View Model class like this.

    <UserControl.DataContext>
        <viewModels:myVMClass></viewModels:myVMClass>
    </UserControl.DataContext>

Now let us look into a button click operation. Remember there will not be any code in the code-behind file because of the button click action. This is how the button click event is wired up.

<Button x:Name="buttonTest" Grid.Row="1" Grid.Column="2" Width="100" Height="25" Content="Perform Test" Command="{Binding PerformTests}" />

The Command is bound with a property called 'PerformTests'.

        private RelayCommand<object> performTests;
        public ICommand PerformTests
        {
            get
            {
                return performTests;
            }
        }

The private variable 'performTests' is initialized like this.

performTests = new RelayCommand<object>(SubmitTest, CanSubmitTest);

This is the RelayCommand class implementation.


public class RelayCommand<T>  : ICommand
    {
        readonly Predicate<object> canExecute;
        readonly Action<object> executeAction;
        public RelayCommand(Action<T> execute)
        {
        }

public RelayCommand(Action<object> inExecuteAction, Predicate<object> inCanExecute)
        {
            if (inExecuteAction == null)
            {
MessageBox.Show("inExecuteAction is null.", "Error", MessageBoxButton.OK);
                return;
            }
            executeAction = inExecuteAction;
            canExecute = inCanExecute;
        }

        bool ICommand.CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            executeAction(parameter);
        }

        event EventHandler ICommand.CanExecuteChanged
        {
            add { }
            remove { }
        }
    }

This is the 'CanSubmitTest' and 'SubmitTest' function implementation.

        public bool CanSubmitTest(object obj)
        {
            return true;
        }
        public void SubmitTest(object obj)
        {
            CallAnyFunctionforButtonClickAction();
        }

In the function 'SubmitTest' call the button click action function.

Hope this article gives a basic idea of the MVVM implementation. I will try to cover the MVVM AutoComplete box implementation in my next post.

Happy coding.

Cheers
Anand




 

Tuesday, March 26, 2013

Creating Unique Application ID for Silverlight Applications


In one of my projects, it became necessary to run a portion of the code only in my computer. This was a Silverlight Application and there were many developers working on this. This section of the code was unique to my computer alone and we need to execute this code only from my computer. After digging around for an answer, finally we came across this solution.
Silverlight provides an ability to store data in “Isolated Storage”. Using this technique we store a unique key in my computer (source code shown below). First time, we examine this key in ‘Debug Mode’ and then copy and hard code this. In the main calling function we check for this ‘Unique Key’. If it matches then we execute the special code pertaining to my computer alone.
Hope this helps someone.

Cheers
Anand
========== Calling Code Begins ==================

If (GetUniqueAppID() == “Hardcoded Unique Key Code”)
{

// Execute this special portion of this code unique for my machine and this application

}
========== Calling Code Ends ==================

========== Unique Key Generating Code ===========

        private string GetUniqueAppID()
        {
            string keyname = "UniqueAppID";
            string key = "";
            try
            {
                if (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Contains(keyname))
                    key = (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings[keyname] ?? "").ToString();
                if (string.IsNullOrEmpty(key))
                {
                    key = Guid.NewGuid().ToString();
                    System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings[keyname] = key;
                }
            }
            catch
            {
                key = "";
            }
            return key;
        }


========== Unique Key Generating Code ===========

 

 

Sunday, February 24, 2013

Using reflection in Silverlight


Reflection is a technique, which provides objects that encapsulate assemblies, modules, and types. Using this technique, you can call a method or set/get values of properties of a class object during runtime.

Here is a sample code snippet.

private void HidePhotoControl()
{
if (_MainPage == null) return;
System.Type _MainPageClassType = _MainPage.GetType();
_ MainPageClassType.InvokeMember("DisablePhotoControl", BindingFlags.InvokeMethod, null, _MainPage, null);
}

 As you can see here, the _MainPage contains a “PhotoControl” and the aim is to disable it. There is a method on the _MainPage called ‘DisablePhotoControl();’. If this function is called then it will simply disable the photo control by turning off the visibility property of it.

 But how to call this function from a different class, assuming that this other class does not have access to the Mainpage class? This is where the reflection technique helps.

 As seen in the code snippet, first make sure the main page pointer is not null. Then get the class type of the main page pointer. Finally using the main page class type to invoke the method call.

 It works like a charm!

 Happy coding!

Saturday, January 19, 2013

Reading files in Silverlight Application

There was a request to read information from a text file in my silverlight application. When I did the coding and testing, I tried to hardcode the path and read the file using "StreamReader" class. This was not working because silverlight was throwing security exception error.

After some trial and error, I discovered that the user must be prompted to select a file and only that selected file can be read through the application.

Here is the sample code.

private void Load_Click(object sender, RoutedEventArgs e)
{
Stream fs = null;
try
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "xml files (*.xml)|*.xml";
ofd.Multiselect = false;
bool? userClickedOK = ofd.ShowDialog();
if (userClickedOK == true)
{
fs = ofd.File.OpenRead();
using (System.IO.StreamReader reader = new System.IO.StreamReader(fs))
{
XmlReader xmlReader = XmlReader.Create(reader);
List<GraphicObject> savedGraphics = XMLDeserialize<List<GraphicObject>>(xmlReader);
DisplayAllGraphicsData(savedGraphics);
this.graphicsLayer.Refresh();
fs.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
}

The "using" statement is the key here. Any file reading must happen inside this "using" block.

Hope this tip helps!

Cheers
Anand

Saturday, December 22, 2012

Restoring ArcSDE SQL Database from SQL Backup File

In one of my projects I was given a SQL backup file (.bak) file and was told that this is an ArcGIS ArcSDE Database.

My task was to restore it into our ArcSDE Environment.

Here are few simple steps/tips on how to perform this task.

1. Use SQL Restore Command and restore the database.

2. It is very important to restore it to the same 'Original Database Name'. If this is not the case then it will not work correctly.

3. After restoring, in the restored database, there will be many users from the client environment. Verifiy if there is a 'sde' user. If there is a 'sde' user then run the following script in SQL. It is also assumed that in your environment there is a 'sde' user.

EXEC sp_change_users_login 'Update_One', 'sde', 'sde'

4. Make sure your 'sde' login is mapped to the newly restored database. The schema name should be same as the user name which is 'sde'.

5. Verify that the 'sde' user has the following permissions

CREATE TABLE
CREATE PROCEDURE
CREATE FUNCTION
CREATE VIEW
CONNECT
VIEW DATABASE STATE

6. Now establish a connection from 'ArcCatalog' as 'sde' user and you will be able to see the GIS data.

Have fun !

Cheers
Anand

Friday, November 23, 2012

ESRI Javascript API - Adding a Graphic

It's easy to add Graphic on the Map using ESRI's Javascript API.

This function calls to add graphic.

addGraphic(map, getPoint(lngsign, photoLng, latsign, photoLat), photoFileName, photoThumbNail, photoTitle, photoDesc);

This function gets the Point Geometry based on Lat and Long.

function getPoint(lngsign, x, latsign, y) {
    var togoPoint = esri.geometry.geographicToWebMercator(new esri.geometry.Point(lngsign * x, latsign * y, new esri.SpatialReference({ wkid: 4326 })));
    return togoPoint;
}


This function adds the Graphic to the Map Control.
function addGraphic(map, geometry, fileName, thumbnailName, title, description)
{
    var symbol = null;
    var pointSymbol = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_SQUARE, 10, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 0, 0]), 1), new dojo.Color([0, 0, 255, 0.9]));
    var lineSymbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 0, 0]), 1);
    var polySymbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASHDOT, new dojo.Color([255, 0, 0]), 2), new dojo.Color([255, 255, 0, 0.5]));
    var type = geometry.type;
    if (type === "point" || type === "multipoint") {
        symbol = pointSymbol;
    }
    else if (type === "line" || type === "polyline") {
        symbol = lineSymbol;
    }
    else {
        symbol = polySymbol;
    }
    var newGraphic = new esri.Graphic(geometry, symbol);
    var infoTemplate = new esri.InfoTemplate(); infoTemplate.setTitle(title);
    var imageContent = GetImageContent(fileName, thumbnailName, description);
    infoTemplate.setContent(imageContent);
    newGraphic.setInfoTemplate(infoTemplate);
    map.graphics.add(newGraphic);
   
}


Make sure that all these calls are done after the Map control is initialized.
This is the init() function. As you can notice the "onUpdateEnd" function ensures that the map is updated. All other javascript functions can be called after this event has fired.

function init()
{
    adjustWindowDimensions();
    map = new esri.Map("divMap");
    var tiledMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer");
    map.addLayer(tiledMapServiceLayer);
    var startExtent = new esri.geometry.Extent(-24440281.172008913, -342437.886717527, 2289441.8711969512, 10419895.695832416);
    map.setExtent(startExtent);
    dojo.connect(map, "onMouseMove", showCoordinates);
    dojo.connect(map, "onMouseDrag", showCoordinates);
    dojo.connect(window, 'resize', map, map.resize);
    dojo.connect(map, "onUpdateEnd", hideStatus);
    dojo.connect(map, "onUpdateStart", showStatus);
    dojo.connect(map, "onExtentChange", mapExtentModified);
}
 Happy Coding !

Cheers
Anand
 

Saturday, October 6, 2012

RichTextBox in Silverlight

Team,

Here is a simple code to implement "RichTextBox" in silverlight.

Call this function WriteTextintoRichTextBox() and send in the message to be shown in the textbox.

Happy coding.

Cheers
Anand

The XAML file content:

<Border Background="Red" Width="300" Height="300" VerticalAlignment="Bottom" HorizontalAlignment="Left" CornerRadius="10">
<RichTextBox x:Name="richTextBox" Margin="5,5,5,5" IsReadOnly="True" >
</RichTextBox>
</Border>

The CS file content:

private void WriteTextintoRichTextBox(string toWriteInfo)
{
Paragraph rtbPara = new Paragraph();
Run rtbRun = new Run();
rtbRun.Text = toWriteInfo;
LineBreak rtbLineBreak = new LineBreak();
rtbPara.Inlines.Add(rtbRun);
this.richTextBox.Blocks.Add(rtbPara);
this.richTextBox.SelectAll();
}

Sunday, September 30, 2012

Map Scale in ESRI Silverlight API


To display better scale information on the map, it's recommended to use the following technique.

1.       As always use the ESRI “ScaleLine” control for the Map.

2.       Utilize the property changed event of this control and then compute the scale to display.

Here is the sample code.
 

XAML code:

<StackPanel Orientation="Vertical">
<TextBlock x:Name="textBlockScaleVaue" Text="Scale" Margin="5,5,5,1" Foreground="White" FontSize="10"
FontStyle="Normal" FontWeight="Normal" Opacity="1.0"/>
<esri:ScaleLine Opacity="1.0" Map="{Binding ElementName=mapControl}" Margin="5,1,5,5" IsHitTestVisible="False" Foreground="White"
Name="scaleLine" MapUnit="Miles" PropertyChanged="scaleLine_PropertyChanged" >
</esri:ScaleLine>
</StackPanel>

.cs file code:

private void scaleLine_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
double currentMapscale = scaleLine.USValue;
ESRI.ArcGIS.Client.Toolkit.ScaleLine.ScaleLineUnit currentMapunit = scaleLine.USUnit;
double valueinInches = 0.0;
if (currentMapunit == ESRI.ArcGIS.Client.Toolkit.ScaleLine.ScaleLineUnit.Feet)
{
valueinInches = 12.0 * currentMapscale;
}
else if (currentMapunit == ESRI.ArcGIS.Client.Toolkit.ScaleLine.ScaleLineUnit.Miles)
{
valueinInches = 12.0 * 5280.0 * currentMapscale;
}
this.textBlockScaleVaue.Text = "Scale: 1:" + valueinInches.ToString("#,##0.##");
}

Hope this tip helps.

 Happy programming!

 

 

 

All Blogs so far ...