Samstag, 17. Juli 2010

Silverlight: Dataform Required field data UI customizing

If you use a dataform with the autogenerate property set to true, you can customize the behaviour and the look and feel of the dataform in the OnAutoGeneratingField Event.

For example you can set the look and feel of required fields to your individual style.

1. step: DataAnnotation for your properties
   1:  
   2:             [Display(Name = "WKN", ResourceType = typeof(DataResources), Order = 7)]
   3:             [StringLength(6, ErrorMessageResourceName = "ValidationErrorStringTooLong", ErrorMessageResourceType = typeof(ErrorResources))]
   4:             [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", ErrorMessageResourceType = typeof(ErrorResources))]
   5:             public string WKN { get; set; }


2. step: Override OnAutoGeneratingField

Define your own DataForm control which inherits from DataForm. Then you can override the OnAutoGeneratingField method and do a lot of tricky things. Manipulating the behaviour of your autogenerated datafields or give them a different style. In my example we used in our project this mechanism to attach a GotFocus and LostFocus-Event to each TextBox and DatePicker, if there is a Required-Attribute defined.

   1: RequiredAttribute requiredAttribute = (RequiredAttribute)(from Attribute a in customAttributes 
   2:                   where a is RequiredAttribute select a).FirstOrDefault();
   3:  
   4: if (requiredAttribute != null) 
   5: {
   6:     if ((e.Field.Content is TextBox) || (e.Field.Content is DatePicker))
   7:     {
   8:         ((Control)e.Field.Content).GotFocus += new RoutedEventHandler(BilanzObjektDataForm_GotFocus);
   9:         ((Control)e.Field.Content).LostFocus += new RoutedEventHandler(BilanzObjektDataForm_LostFocus);
  10:     }
  11: }

The GotFocus- and LostFocus-Events looks like this:

   1: void BilanzObjektDataForm_LostFocus(object sender, RoutedEventArgs e)
   2:         {
   3:             // State auf "kein" Pflichtfeld setzen.
   4:             // State "normal" kann nicht definiert werden, da dieser eindeutig benamt werden muss
   5:             VisualStateManager.GoToState((Control)sender, "NotRequired", true);
   6:         }
   1: void BilanzObjektDataForm_GotFocus(object sender, RoutedEventArgs e)
   2:         {
   3:             // die Pflichtfeld-Behandlung gilt nur für TextBox- und DatePicker-Controls
   4:             // und nur dann, wenn der Text leer ist
   5:             if (((sender is TextBox) && (String.IsNullOrEmpty(((TextBox)sender).Text))) || 
   6:                 ((sender is DatePicker) && (String.IsNullOrEmpty(((DatePicker)sender).Text))))
   7:             {
   8:                 // State auf Pflichtfeld setzen
   9:                 VisualStateManager.GoToState((Control)sender, "Required", true);
  10:             }
  11:         }

In this Eventhandlers we use the VisualStateManager to give the controls, if the content is empty, a new visual state “Required” or in the other case the visual state “NotRequired”.

Now you have only to define the two new states in your style and you can enjoy the new Required field effect.

3. step: Add new States to your style

In the VisualStateManager section:

   1: <VisualStateGroup x:Name="RequiredStates">
   2:                                <VisualState x:Name="NotRequired">
   3:                                    <Storyboard>
   4:                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PflichtfeldInfo">
   5:                                            <EasingDoubleKeyFrame KeyTime="0" Value="0"/>                                            
   6:                                        </DoubleAnimationUsingKeyFrames>
   7:                                    </Storyboard>
   8:                                </VisualState>
   9:                                <VisualState x:Name="Required">
  10:                                    <Storyboard>
  11:                                        <Storyboard>
  12:                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PflichtfeldInfo">                                                
  13:                                                <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1" >
  14:                                                    <EasingDoubleKeyFrame.EasingFunction>
  15:                                                        <CubicEase EasingMode="EaseOut"/>
  16:                                                    </EasingDoubleKeyFrame.EasingFunction>
  17:                                                </EasingDoubleKeyFrame>
  18:                                                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0"/>
  19:                                            </DoubleAnimationUsingKeyFrames>
  20:                                        </Storyboard>                                        
  21:                                    </Storyboard>
  22:                                </VisualState>
  23:                            </VisualStateGroup>

The content style:

   1: <Grid  >                              
   2:                                 <ScrollViewer x:Name="ContentElement" 
   3:                                               BorderThickness="0"
   4:                                               IsTabStop="False"
   5:                                               Margin="4,0,2,2"
   6:                                               VerticalAlignment="Center"  />
   7:                                 <TextBlock x:Name="PflichtfeldInfo"
   8:                                    Text="Pflichtfeld"
   9:                                    Style="{StaticResource PflichtfeldStyle}"
  10:                                    Opacity="0" />
  11:                             </Grid>                            
  12:                         </Grid>

Samstag, 10. Juli 2010

RIA Services: Windows Phone 7 and SOAP endpoint

You can use RIA services as a normal WCF service with several clients. For example as Excel OData-Source or as data delivery service for your Windows Phone 7 application. To achieve this goal you have to install the latest RIA Services Toolkit and do a little configuration work.

Reference for Microsoft.ServiceModel.DomainServices.Hosting

Add a reference of Microsoft.ServiceModel.DomainServices.Hosting to your RIA Services project.

It is important that you choose the version which was shipped by the RIA Services (Silverlight) toolkit. The standard standard assembly from the SDK does not contain the SoapXmlEndpointFactory and JSonEndpointFactory.

So take this one:

image

For the OData endpoint you need the System.ServiceModel.DomainServices.Hosting.OData assembly from the SDK directory.

Configure the endpoints

Configure the Json, Soap and OData endpoints in the web.config:

<system.serviceModel>
      <domainServices>
        <endpoints>
          <add name="Soap" 
               type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add name="Json" 
               type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add name="OData"
               type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </endpoints>
      </domainServices>
       <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
     </system.serviceModel>
Using of RIA Services in your Windows Phone 7 application

To use the rias service (Soap endpoint) in your Windows Phone 7 application you have only to add a new reference and enter the Uri of your ria service.

Your Uri consists of the <namespace of your ria service>-<classname of your ria service>.svc where “.” are replaced with “-“ !

image

 

Now you can create a proxy client and access to your Domainservice methods:

   1: public partial class MainPage : PhoneApplicationPage
   2:     {
   3:         object _selectedItem;
   4:         PrivatbilanzService.FinancialPlanningDomainServiceSoapClient client;
   5:  
   6:         public MainPage()
   7:         {
   8:             InitializeComponent();
   9:  
  10:             client = new PrivatbilanzService.FinancialPlanningDomainServiceSoapClient();
  11:  
  12:             SupportedOrientations = SupportedPageOrientation.Portrait;
  13:             Loaded += new RoutedEventHandler(MainPage_Loaded);
  14:  
  15:             PageTransitionList.Completed += new EventHandler(PageTransitionList_Completed);
  16:  
  17:             // Set the data context of the listbox control to the sample data
  18:             DataContext = new MainViewModel();
  19:         }

 

Uri of all endpoints

The Uri for our exposed endpoints are:

OData : http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc/OData/

SOAP: http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc

JSON: http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc/JSON/

With these exposed endpoints, you can talk to multiple clients:

  • Excel Power pivot - Using the OData endpoint
  • Windows Phone 7 – Using the SOAP endpoint
  • AJAX client – Using the JSON endpoint

Samstag, 3. Juli 2010

Silverlight: Converter with multiple parameters

Sometimes it is necessary that you have a converter (interface IValueConverter) with multiple parameters. To reach this goal, you can use a DependencyProperty. That’s normally a very easy step, but I spend some extraordinary time with my converter becuase in my case the second parameter should be bindable

– So what was the problem?

I have tried to derive the Converter from UserControl – great mistake: You have to use FrameworkElement instead!

Usage:
   1: <Helpers:StatisticsConverter x:Key="StatisticsConverter" ViewModel="{Binding ElementName=LayoutRoot,Path=DataContext.Statistics}" />
   2:     
   3: <TextBlock Margin="0,0,10,0"
   4:    FontSize="9"  
   5:    x:Name="InfoSummeText" Text="{Binding Converter={StaticResource StatisticsConverter}, ConverterParameter=Summe}" >
   6: </TextBlock>
Converter:
   1: public class StatisticsConverter : FrameworkElement, IValueConverter
   2:    {
   3:  
   4:        #region IValueConverter Members
   5:  
   6:        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   7:        {
   8:            var statisticsViewModel = (StatisticsViewModel)ViewModel;
   9:            var statistics = statisticsViewModel.GetAnzeigeKategorieStatistics(value as AnzeigeKategorie);
  10:            switch (parameter.ToString())
  11:            {
  12:                case "Summe":
  13:                    {
  14:                        return String.Format("{0:N2}", statistics.Summe) + " EUR";
  15:                    }
  16:                default:
  17:                    {
  18:                        throw new NotImplementedException(parameter as string);
  19:                    }
  20:            }
  21:        }
  22:  
  23:        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  24:        {
  25:            return "";
  26:        }
  27:  
  28:        #endregion
  29:  
  30:        #region object ViewModel (DependencyProperty)
  31:  
  32:        public object ViewModel
  33:        {
  34:            get { return (object)GetValue(ViewModelProperty); }
  35:            set { SetValue(ViewModelProperty, value); }
  36:        }
  37:  
  38:        public static readonly DependencyProperty ViewModelProperty =
  39:            DependencyProperty.Register(
  40:                "ViewModel",
  41:                typeof(object),
  42:                typeof(StatisticsConverter),
  43:                new PropertyMetadata(null, null));
  44:  
  45:  
  46:        #endregion ViewModel (DependencyProperty)
  47:    }

Freitag, 2. Juli 2010

Silverlight Toolkit: Disable Drag for DragDropTarget

Each of the new DragDropTarget-Controls in the Silverlight Toolkit have a property AllowDrop which you can use to disable or enable the drop behaviour. But if you want to disable the underlaying controls to be draggable you have to cancel the drag start event at the ItemDragStarting Event:

1. Add Event handler
   1: <toolkit:TreeViewDragDropTarget ExpandNodeDelay="500"
   2:     AllowDrop="True" Drop="OnItemDropped" ItemDragStarting="TreeViewDragDropTarget_ItemDragStarting"
   3:     HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Top" >
2. Define the event handler
   1: private void TreeViewDragDropTarget_ItemDragStarting(object sender, ItemDragEventArgs e)
   2:         {
   3:             e.Cancel = true;
   4:             e.Handled = true;
   5:         }