AWG Blogs

Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Friday, February 15, 2013

Bind ViewModel Declaratively with Caliburn.Micro in Non-Caliburn.Micro App

I have an existing Silverlight App with Frame based navigation and the app is fairly stable. I wanted to look into logging interception of ViewModels and that is when I started testing Caliburn.Micro (per an answer to my question here). My aim is to gradually migrate pages over to the Caliburn.Micro framework, but not have CM take over the App at first (i.e. set the RootVisual). The closes discussion on the web I could find regarding this scenario was http://caliburnmicro.codeplex.com/discussions/260738. To do a proof-of-concept I simply combined the files from the Caliburn.Micro.ViewFirst sample project with a SL Nav template project:

- Create a new "Silverlight Navigation Application" project
-Add existing files from ViewFirst sample: IShell.cs, MefBootstrapper.cs, and ShellViewModel.cs (change namespaces if desired)
- Add necessary references to MEF and Caliburn.Micro
- In MefBootstrapper, remove the OnStartup override method, since we are not setting the rootvisual, but instead letting the App.xaml do that. Note I thought it was necessary to also override the constructor and set "base(false)" but it seems to work either way, so I left it out.
- Copy the StackPanel element and its content from ShellView.xaml into the ContentStackPanel of About.xaml
- For the declarative binding of VM, also add the following also to About.xaml:     cal:Bind.Model="Shell"  xmlns:cal="http://www.caliburnproject.org"
- At the top of the App constructor of App.xaml.cs add:             new MefBootstrapper();
- Press F5, click "About" and notice that you have a working Caliburn.Micro ViewModel View with Actions all wired up automatically!

Monday, February 11, 2013

IsolatedStorageException - "Initialization Failed"

I got this IsolatedStorageException - message: "Initialization Failed" - when using Enterprise Library. The line giving the error is in StorageAccessor.Silverlight.cs
            this.store = IsolatedStorageFile.GetUserStoreForApplication();
I've gotten this error before in other circumstances, and usually occur right after I delete the Isolated Storage for a particular URL and reopen the app.

Tried rebooting, recompiling, reinstalling Silverlight runtime. Finally what worked was deleting this folder: C:\Users\User.Name\AppData\LocalLow\Microsoft\Silverlight

Apparently there is some corrupted state left over in there. I also noted that around this time I was unable to delete other app stores.

Sunday, January 13, 2013

Dev on Alternate Machine

This is for when you want to work on a different SharePoint 2007 dev machine but not have to change host name configuration entries in your Silverlight code.

- edit the Windows hosts file adding
127.0.0.1 yourPrimaryServerName

- add yourPrimaryServerName as a public url for the intranet zone of your web app in the alternate access mappings

- add a host header value of "yourPrimaryServerName" to the site's IIS 6 configuration

- set DisableLoopbackCheck see http://support.microsoft.com/kb/896861
- add the following files to c:\inetpub\wwwroot (or a subdir, check IIS for the actual root dir the 80 site)

clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>

<grant-to>
<resource include-subpaths="true" path="/"></resource>
</grant-to>
</policy>
</cross-domain-access>

</access-policy>

crossdomain.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- The file must be configured to allow access to the service from any other domain,
or it is not recognized by Silverlight 4.
Save the crossdomain.xml file to the root of the domain where the service is hosted.
If, for example, the service is hosted in http://fabrikam.com,
then the file must be located at http://fabrikam.com/crossdomain.xml.
-->
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*"/>

</cross-domain-policy>
ref

Monday, December 3, 2012

Finding Collapsed Groups in DataGrid

This question came up here, which I found when searching a solution to same problem.

Here is some code that solves this issue:

            List<string> grpItems = new List();
            string groupby = "";
            foreach (var control in dataGrid1.GetVisuals().OfType<DataGridRowGroupHeader>())
            {

                var tog = XamlUtils.FindVisualChild<ToggleButton>(control);
                var context = control.DataContext as CollectionViewGroup;
                string nm = context.Name.ToString();
                bool? chk = tog.IsChecked;
                if (chk != null && (bool)chk)
                {
                    grpItems.Add(nm);
                }
                groupby = control.PropertyName;
            }



The methods in XamlUtils are FindVisualChild and GetVisuals which can be found at http://blogs.msdn.com/b/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx and http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx respectively.
Note: To get this to work, for some reason, it required removal of any filters on the PagedCollectionView.

Monday, September 17, 2012

Debugging Silverlight to SSL'd SharePoint .asmx from VS

As explained here, there are a few steps you need to take to enable this scenario, i.e. to get around:

An error occurred while trying to make a request to URI 'https://machinename/_vti_bin/Lists.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.

Copy the following files to C:\inetpub\wwwroot\wss\VirtualDirectories\443: crossdomain.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- The file must be configured to allow access to the service from any other domain, 
or it is not recognized by Silverlight 4.
Save the crossdomain.xml file to the root of the domain where the service is hosted. 
If, for example, the service is hosted in http://fabrikam.com, 
then the file must be located at http://fabrikam.com/crossdomain.xml.
-->
<!DOCTYPE cross-domain-policy SYSTEM 
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
  
</cross-domain-policy>
clientaccesspolicy.xml:
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
              <domain uri="http://*"/>
              <domain uri="https://*"/>
            </allow-from>

      <grant-to>
        <resource include-subpaths="true" path="/"></resource>
      </grant-to>
    </policy>
  </cross-domain-access>
  
</access-policy>
Note the subpaths="true"! Then open https://machinename/clientaccesspolicy.xml in browser (BTW verify its wellformed xml), accept the security warning, then click Certificate Error, View Certificate, then Install Certificate..., Next, then "Place all certificates in the following store", select "Trusted Root Certification Authorities", OK. After that, you should be able to F5 your Visual Studio 2010 Silverlight 5 app, and load your data from the SSL enabled Sharepoint 2007 web service. Ref1, ref2

Sunday, September 9, 2012

Set ClickMode to Press to Avoid Losing Click Event in DataGrid Column But Note Caveats

For some reason, I was losing the click event for a button in a DataGridTemplateColumn; i.e. the click event (and associated command) would not fire after editing another cell and immediately clicking the (delete) button in the far left column. Setting the ClickMode to Press (rather than the default of Release) appears to fix the issue; i.e. once that is done, the event fires, and I do not have to click Delete twice. There are a couple of steps to take in addition if the DataGrid is bound to a PagedCollectionView that you intend to Refresh() immediately, i.e. within the called Command. These are so as to avoid the error:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.Data but was not handled in user code

Additional information: 'Refresh' is not allowed during an AddNew or EditItem transaction.
1) Add a GotFocus="Button_GotFocus" to the event with method:
        private void Button_GotFocus(object sender, RoutedEventArgs e)
        {
            dataGrid1.CommitEdit(DataGridEditingUnit.Row, true);
        }
Evidently, GotFocus fires before Click here, so it is the place to exit Edit mode.
2) Wrap the pagedCollectionView.Refresh() call in an asynchronous call:

    Deployment.Current.Dispatcher.BeginInvoke(
    () =>
    {
        pagedCollectionView.Refresh();
    });
Evidently, the asynch call delays the refresh long enough so that the row can exit edit mode. These are workarounds that signal a compromise with MVVM and elegance in general, but until I find a better solution, it is what it is.

Use Explicit Binding to Force Update on TextChanged

If you have a TextBox inside a DataTemplate in a DataGrid, and want any TextChanged event to update the binding, set Mode=TwoWay, UpdateSourceTrigger=Explicit on the binding or else you will get an error:
"Operation is not valid due to the current state of the object."

More Notes:

Since this is an Explicit binding, you will need to hook to the event using a behavior such as Prism's UpdateTextBindingOnPropertyChanged. But since that has been made obsolete in Silverlight 5 you will need to get the class itself from the Prism code and add it to your project manually and then attach that like so:
                        <data:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                                <TextBox Height="23" HorizontalAlignment="Left"  
Name="textBox1" VerticalAlignment="Top" Width="120" 
                 
Text="{Binding Invmprop, Mode=TwoWay}" >

                                    <i:Interaction.Behaviors>
                                        <local:MyUpdateTextBindingOnPropertyChanged />
                                    </i:Interaction.Behaviors>
                                </TextBox>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellEditingTemplate>
Why is it obsolete? Because Silverlight 5 introduced UpdateSourceTrigger=PropertyChanged, which works fine in uncontained textboxes but not when they are in DataGrids (or so I've observed), so for those in DataGrids, I had to perform the above workaround.