Applying same interaction trigger to multiple TextBoxes - xaml

I have multiple textboxes bound to different data, but I would like every one to launch the same command when the TextChanged event is fired. I could copy the interaction line under every textbox but I'm guessing there must be a way to use a template or style to get this working on all of them.
Here is the code for the first textbox
<TextBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Height="28" HorizontalAlignment="Stretch" Margin="0,12,12,0" Name="TextBox_Description" VerticalAlignment="Top" TabIndex="3" Text="{Binding Item.Description, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding DataChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

If your UpdateMode is always going to be PropertyChanged then there really isn't any reason not to listen to your own PropertyChangedEvent in your ViewModel. It will definitely improve testability.
private void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
switch (args.PropertyName)
{
case "Prop1":
case "Prop2":
.
.
.
DataChangedCommand.Execute(null);
break;
}
}

I'm not positive how to do it with Interaction.Triggers, but in the past I've used the AttachedCommand dependency properties found here and simply used a Style
Normal XAML
<TextBox local:CommandBehavior.Event="TextChanged"
local:CommandBehavior.Command="{Binding DataChangedCommand}"/>
Using a Style
<Style TargetType="TextBox">
<Setter Property="local:CommandBehavior.Event" Value="TextChanged" />
<Setter Property="local:CommandBehavior.Command" Value="{Binding DataChangedCommand}" />
</Style>
EDIT: Since you can't download files at work, here's the code
CommandBehavior.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Markup;
using System.Windows;
using System.Windows.Input;
// Code to attach a command to any event
// From http://marlongrech.wordpress.com/2008/12/04/attachedcommandbehavior-aka-acb/
namespace Keys.Controls.Helpers.CommandHelpers
{
/// <summary>
/// Defines the attached properties to create a CommandBehaviorBinding
/// </summary>
public class CommandBehavior
{
#region Behavior
/// <summary>
/// Behavior Attached Dependency Property
/// </summary>
private static readonly DependencyProperty BehaviorProperty =
DependencyProperty.RegisterAttached("Behavior", typeof(CommandBehaviorBinding), typeof(CommandBehavior),
new FrameworkPropertyMetadata((CommandBehaviorBinding)null));
/// <summary>
/// Gets the Behavior property.
/// </summary>
private static CommandBehaviorBinding GetBehavior(DependencyObject d)
{
return (CommandBehaviorBinding)d.GetValue(BehaviorProperty);
}
/// <summary>
/// Sets the Behavior property.
/// </summary>
private static void SetBehavior(DependencyObject d, CommandBehaviorBinding value)
{
d.SetValue(BehaviorProperty, value);
}
#endregion
#region Command
/// <summary>
/// Command Attached Dependency Property
/// </summary>
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(CommandBehavior),
new FrameworkPropertyMetadata((ICommand)null,
new PropertyChangedCallback(OnCommandChanged)));
/// <summary>
/// Gets the Command property.
/// </summary>
public static ICommand GetCommand(DependencyObject d)
{
return (ICommand)d.GetValue(CommandProperty);
}
/// <summary>
/// Sets the Command property.
/// </summary>
public static void SetCommand(DependencyObject d, ICommand value)
{
d.SetValue(CommandProperty, value);
}
/// <summary>
/// Handles changes to the Command property.
/// </summary>
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
binding.Command = (ICommand)e.NewValue;
}
#endregion
#region CommandParameter
/// <summary>
/// CommandParameter Attached Dependency Property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(CommandBehavior),
new FrameworkPropertyMetadata((object)null,
new PropertyChangedCallback(OnCommandParameterChanged)));
/// <summary>
/// Gets the CommandParameter property.
/// </summary>
public static object GetCommandParameter(DependencyObject d)
{
return (object)d.GetValue(CommandParameterProperty);
}
/// <summary>
/// Sets the CommandParameter property.
/// </summary>
public static void SetCommandParameter(DependencyObject d, object value)
{
d.SetValue(CommandParameterProperty, value);
}
/// <summary>
/// Handles changes to the CommandParameter property.
/// </summary>
private static void OnCommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
binding.CommandParameter = e.NewValue;
}
#endregion
#region Event
/// <summary>
/// Event Attached Dependency Property
/// </summary>
public static readonly DependencyProperty EventProperty =
DependencyProperty.RegisterAttached("Event", typeof(string), typeof(CommandBehavior),
new FrameworkPropertyMetadata((string)String.Empty,
new PropertyChangedCallback(OnEventChanged)));
/// <summary>
/// Gets the Event property. This dependency property
/// indicates ....
/// </summary>
public static string GetEvent(DependencyObject d)
{
return (string)d.GetValue(EventProperty);
}
/// <summary>
/// Sets the Event property. This dependency property
/// indicates ....
/// </summary>
public static void SetEvent(DependencyObject d, string value)
{
d.SetValue(EventProperty, value);
}
/// <summary>
/// Handles changes to the Event property.
/// </summary>
private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
//check if the Event is set. If yes we need to rebind the Command to the new event and unregister the old one
if (binding.Event != null && binding.Owner != null)
binding.Dispose();
//bind the new event to the command if newValue isn't blank (e.g. switching tabs)
if (e.NewValue.ToString() != "")
binding.BindEvent(d, e.NewValue.ToString());
}
#endregion
#region Helpers
//tries to get a CommandBehaviorBinding from the element. Creates a new instance if there is not one attached
private static CommandBehaviorBinding FetchOrCreateBinding(DependencyObject d)
{
CommandBehaviorBinding binding = CommandBehavior.GetBehavior(d);
if (binding == null)
{
binding = new CommandBehaviorBinding();
CommandBehavior.SetBehavior(d, binding);
}
return binding;
}
#endregion
}
}
CommandBehaviorBinding.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Reflection;
using System.Windows;
// Code to attach a command to any event
// From http://marlongrech.wordpress.com/2008/12/04/attachedcommandbehavior-aka-acb/
namespace Keys.Controls.Helpers.CommandHelpers
{
/// <summary>
/// Defines the command behavior binding
/// </summary>
public class CommandBehaviorBinding : IDisposable
{
#region Properties
/// <summary>
/// Get the owner of the CommandBinding ex: a Button
/// This property can only be set from the BindEvent Method
/// </summary>
public DependencyObject Owner { get; private set; }
/// <summary>
/// The command to execute when the specified event is raised
/// </summary>
public ICommand Command { get; set; }
/// <summary>
/// Gets or sets a CommandParameter
/// </summary>
public object CommandParameter { get; set; }
/// <summary>
/// The event name to hook up to
/// This property can only be set from the BindEvent Method
/// </summary>
public string EventName { get; private set; }
/// <summary>
/// The event info of the event
/// </summary>
public EventInfo Event { get; private set; }
/// <summary>
/// Gets the EventHandler for the binding with the event
/// </summary>
public Delegate EventHandler { get; private set; }
#endregion
//Creates an EventHandler on runtime and registers that handler to the Event specified
public void BindEvent(DependencyObject owner, string eventName)
{
EventName = eventName;
Owner = owner;
Event = Owner.GetType().GetEvent(EventName, BindingFlags.Public | BindingFlags.Instance);
if (Event == null)
throw new InvalidOperationException(String.Format("Could not resolve event name {0}", EventName));
//Create an event handler for the event that will call the ExecuteCommand method
EventHandler = EventHandlerGenerator.CreateDelegate(
Event.EventHandlerType, typeof(CommandBehaviorBinding).GetMethod("ExecuteCommand", BindingFlags.Public | BindingFlags.Instance), this);
//Register the handler to the Event
Event.AddEventHandler(Owner, EventHandler);
}
/// <summary>
/// Executes the command
/// </summary>
public void ExecuteCommand()
{
if (Command != null && Command.CanExecute(CommandParameter))
Command.Execute(CommandParameter);
}
#region IDisposable Members
bool disposed = false;
/// <summary>
/// Unregisters the EventHandler from the Event
/// </summary>
public void Dispose()
{
if (!disposed)
{
Event.RemoveEventHandler(Owner, EventHandler);
disposed = true;
}
}
#endregion
}
}
EventHandlerGenerator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
// Code to attach a command to any event
// From http://marlongrech.wordpress.com/2008/12/04/attachedcommandbehavior-aka-acb/
namespace Keys.Controls.Helpers.CommandHelpers
{
/// <summary>
/// Generates delegates according to the specified signature on runtime
/// </summary>
public static class EventHandlerGenerator
{
/// <summary>
/// Generates a delegate with a matching signature of the supplied eventHandlerType
/// This method only supports Events that have a delegate of type void
/// </summary>
/// <param name="eventInfo">The delegate type to wrap. Note that this must always be a void delegate</param>
/// <param name="methodToInvoke">The method to invoke</param>
/// <param name="methodInvoker">The object where the method resides</param>
/// <returns>Returns a delegate with the same signature as eventHandlerType that calls the methodToInvoke inside</returns>
public static Delegate CreateDelegate(Type eventHandlerType, MethodInfo methodToInvoke, object methodInvoker)
{
//Get the eventHandlerType signature
var eventHandlerInfo = eventHandlerType.GetMethod("Invoke");
Type returnType = eventHandlerInfo.ReturnParameter.ParameterType;
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type. This only supprts event handlers that are void");
ParameterInfo[] delegateParameters = eventHandlerInfo.GetParameters();
//Get the list of type of parameters. Please note that we do + 1 because we have to push the object where the method resides i.e methodInvoker parameter
Type[] hookupParameters = new Type[delegateParameters.Length + 1];
hookupParameters[0] = methodInvoker.GetType();
for (int i = 0; i < delegateParameters.Length; i++)
hookupParameters[i + 1] = delegateParameters[i].ParameterType;
DynamicMethod handler = new DynamicMethod("", null,
hookupParameters, typeof(EventHandlerGenerator));
ILGenerator eventIL = handler.GetILGenerator();
//load the parameters or everything will just BAM :)
LocalBuilder local = eventIL.DeclareLocal(typeof(object[]));
eventIL.Emit(OpCodes.Ldc_I4, delegateParameters.Length + 1);
eventIL.Emit(OpCodes.Newarr, typeof(object));
eventIL.Emit(OpCodes.Stloc, local);
//start from 1 because the first item is the instance. Load up all the arguments
for (int i = 1; i < delegateParameters.Length + 1; i++)
{
eventIL.Emit(OpCodes.Ldloc, local);
eventIL.Emit(OpCodes.Ldc_I4, i);
eventIL.Emit(OpCodes.Ldarg, i);
eventIL.Emit(OpCodes.Stelem_Ref);
}
eventIL.Emit(OpCodes.Ldloc, local);
//Load as first argument the instance of the object for the methodToInvoke i.e methodInvoker
eventIL.Emit(OpCodes.Ldarg_0);
//Now that we have it all set up call the actual method that we want to call for the binding
eventIL.EmitCall(OpCodes.Call, methodToInvoke, null);
eventIL.Emit(OpCodes.Pop);
eventIL.Emit(OpCodes.Ret);
//create a delegate from the dynamic method
return handler.CreateDelegate(eventHandlerType, methodInvoker);
}
}
}

Related

In Xamarin.Forms.UWP, Unable to set Automation ID to custom control, if not used SetNativeControl() method

I am creating a custom control in Xamarin.Forms which is inherited from TemplatedView and using the application in all three platforms. For testing purposes, I need to set Automation ID for all native controls.
Usually, by using AutomationPeer we can set Automation ID to native UWP control from the UWP renderer project. But, in my custom control, I get this. Control is null always.
So, I can’t set Automation ID in UWP renderer class as Forms TemplatedView is a FrameworkElement in UWP.
My query is,
How to get a native element (this.Control) in UWP renderer project for Xamarin.Forms TemplatedView.
How to set Automation Id to native UWP control if this.Control is null.
The code snippet is provided below:
class FormsCustomLayout : TemplatedView
{
public static readonly BindableProperty InputViewProperty =
BindableProperty.Create(nameof(InputView), typeof(View), typeof(FormsCustomLayout), null, BindingMode.Default, null, OnInputViewChanged);
private static void OnInputViewChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as FormsCustomLayout).OnInputViewChanged(oldValue, newValue);
}
private void OnInputViewChanged(object oldValue, object newValue)
{
var oldView = (View)oldValue;
if (oldView != null)
{
if (this.contentGrid.Children.Contains(oldView))
{
oldView.SizeChanged -= OnInputViewSizeChanged;
oldView.BindingContext = null;
this.contentGrid.Children.Remove(oldView);
}
}
var newView = (View)newValue;
if (newView != null)
{
newView.SizeChanged += OnInputViewSizeChanged;
newView.VerticalOptions = LayoutOptions.CenterAndExpand;
newView.HeightRequest = 60;
this.contentGrid.Children.Add(newView);
}
}
private void OnInputViewSizeChanged(object sender, EventArgs e)
{
}
public View InputView
{
get { return (View)GetValue(InputViewProperty); }
set { SetValue(InputViewProperty, value); }
}
internal void UpdateText(object text)
{
this.Text = (string)text;
}
private readonly Grid contentGrid = new Grid();
public FormsCustomLayout()
{
this.ControlTemplate = new ControlTemplate(typeof(StackLayout));
((StackLayout)Children[0]).Children.Add(this.contentGrid);
if (InputView != null)
{
this.contentGrid.Children.Add(InputView);
}
}
internal string Text { get; private set; }
}
The custom renderer code snippet is provided below:
class FormsCustomLayoutRenderer : ViewRenderer<FormsCustomLayout, FrameworkElement>
{
/// <summary>
/// Method that is called when the automation id is set.
/// </summary>
/// <param name="id">The automation id.</param>
protected override void SetAutomationId(string id)
{
if (this.Control == null)
{
base.SetAutomationId(id);
}
else
{
this.SetAutomationPropertiesAutomationId(id);
this.Control.SetAutomationPropertiesAutomationId(id);
}
}
/// <summary>
/// Provide automation peer for the control
/// </summary>
/// <returns>The TextInputLayout view automation peer.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
if (this.Control == null)
{
return new FormsCustomLayoutAutomationPeer(this);
}
return new FormsCustomLayoutAutomationPeer(this.Control);
}
protected override void OnElementChanged(ElementChangedEventArgs<FormsCustomLayout> e)
{
base.OnElementChanged(e);
var element = e.NewElement;
}
}
internal class FormsCustomLayoutAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="FormsCustomLayoutRenderer"/> class.
/// </summary>
/// <param name="owner">FormsCustomLayout View control</param>
public FormsCustomLayoutAutomationPeer(FrameworkElement owner) : base(owner)
{
}
/// <summary>
/// Describe the control type
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
/// <summary>
/// Describe the class name.
/// </summary>
/// <returns>The Class Name.</returns>
protected override string GetClassNameCore()
{
return "FormsCustomLayout";
}
}
Demo sample attached here: FormsCustomControl
Please share your idea or solution to set Automation ID.
Regards,
Bharathiraja.

WCF - Error Handling - Creator of this service did not specify a Reason

There are lot of threads with the same error but I could not find a suitable answer so putting it again.
I have a wcf service and I have error handling in place and when I test the service from the wcftestclient all I get is this error info and not the original error that actually occurred.
The creator of this fault did not specify a Reason. Server stack trace: at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at ...
I am not sure why its not returning me the actual error. My error handling code is given below.
/// <summary>
/// Gets the holidays.
/// </summary>
/// <returns>List<HolidayProfile></returns>
[OperationContract]
[FaultContract(typeof(ExceptionFaultContract))]
List<HolidayProfile> GetHolidays();
public List<HolidayProfile> GetHolidays()
{
List<HolidayProfile> holidayProfileList = new List<HolidayProfile>();
try
{
customerBL = new CustomerBL(new CustomerRepository());
holidayProfileList = customerBL.GetHolidays();
}
catch (CustomException ex)
{
throw new FaultException<ExceptionFaultContract>(DBHelper.MapException(ex));
}
return holidayProfileList;
}
I have used two custom Exception classes here. One which is derived from Exception and other is the one which will be passed between the service and client
/// <summary>
/// Class CustomException.
/// </summary>
/// <seealso cref="System.Exception" />
public class CustomException : Exception
{
/// <summary>
/// Gets or sets the error code.
/// </summary>
/// <value>The error code.</value>
public string ErrorCode { get; set; }
/// <summary>
/// Gets or sets the error detail.
/// </summary>
/// <value>The error detail.</value>
public string ErrorDescription { get; set; }
/// <summary>
/// Gets or sets the error number.
/// </summary>
/// <value>The error number.</value>
public int ErrorNumber { get; set; }
}
and another which is the datacontract.
/// <summary>
/// Class ExceptionFaultContract.
/// </summary>
[DataContract]
public class ExceptionFaultContract : Exception
{
/// <summary>
/// Gets or sets the error code.
/// </summary>
/// <value>The error code.</value>
[DataMember]
public string ErrorCode { get; set; }
/// <summary>
/// Gets or sets the error number.
/// </summary>
/// <value>The error number.</value>
[DataMember]
public int ErrorNumber { get; set; }
/// <summary>
/// Gets or sets the error description.
/// </summary>
/// <value>The error description.</value>
[DataMember]
public string ErrorDescription { get; set; }
}
My method in the dataacess.
public List<HolidayProfile> GetHolidays()
{
Initializations
try
{
Code here...
}
catch (OracleException ox)
{
throw (DBHelper.HandleOracleException(ox));
}
catch (Exception ex)
{
throw (DBHelper.HandleException1(ex));
}
finally
{
if (connection != null)
connection.Close();
if (command != null)
command = null;
if (dataAdapter != null)
dataAdapter = null;
dataSet.Dispose();
}
return holidayProfileList;
}
My helper class which does the mapping.
/// <summary>
/// Handles the exception.
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns>ExceptionFaultContract.</returns>
public static CustomException HandleException(Exception ex)
{
CustomException customException = new CustomException();
customException.ErrorDescription = ex.Message;
return customException;
}
/// <summary>
/// Maps the exception.
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns>ExceptionFaultContract.</returns>
public static ExceptionFaultContract MapException(CustomException ex)
{
ExceptionFaultContract exceptionFaultContract = new ExceptionFaultContract();
exceptionFaultContract.ErrorCode = ex.ErrorCode;
exceptionFaultContract.ErrorNumber = ex.ErrorNumber;
exceptionFaultContract.ErrorDescription = ex.ErrorDescription;
return exceptionFaultContract;
}
I m getting an error if I m using the ExceptionFaultContract to be returned from data access ("Error : should be a type derived from exception") and If I try to derive the same from Exception another error saying it cannot be both serializable and derived member or something like that..
I tried lot of things nothing is clear to me...could somebody please help.

In WCF BehaviorExtension BeforeSendRequest method is not getting called?I m stuck please help me...below is code

Here is code for the which I m trying.I want to modify the request packet of service. Genarally the request header,body and action
[CustomBehavior]
public class Service1 : IService1
{
.....
......
}
public class CustomHeader : MessageHeader
{
.....
.....
....
}
/// <summary>
/// This class is used to inspect the message and headers on the server side,
/// This class is also used to intercept the message on the
/// client side, before/after any request is made to the server.
/// </summary>
public class CustomMessageInspector : IClientMessageInspector, IDispatchMessageInspector
{
#region Message Inspector of the Service
/// <summary>
/// This method is called on the server when a request is received from the client.
/// </summary>
/// <param name="request"></param>
/// <param name="channel"></param>
/// <param name="instanceContext"></param>
/// <returns></returns>
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
{
// Create a copy of the original message so that we can mess with it.
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
Message messageCopy = buffer.CreateMessage();
// Read the custom context data from the headers
ServiceHeader customData = CustomHeader.ReadHeader(request);
// Add an extension to the current operation context so
// that our custom context can be easily accessed anywhere.
ServerContext customContext = new ServerContext();
if (customData != null)
{
customContext.KerberosID = customData.KerberosID;
customContext.SiteminderToken = customData.SiteminderToken;
}
OperationContext.Current.IncomingMessageProperties.Add(
"CurrentContext", customContext);
return null;
}
/// <summary>
/// This method is called after processing a method on the server side and just
/// before sending the response to the client.
/// </summary>
/// <param name="reply"></param>
/// <param name="correlationState"></param>
public void BeforeSendReply(ref Message reply, object correlationState)
{
// Do some cleanup
OperationContext.Current.Extensions.Remove(ServerContext.Current);
}
#endregion
#region Message Inspector of the Consumer
/// <summary>
/// This method will be called from the client side just before any method is called.
/// </summary>
/// <param name="request"></param>
/// <param name="channel"></param>
/// <returns></returns>
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Prepare the request message copy to be modified
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
ServiceHeader customData = new ServiceHeader();
customData.KerberosID = ClientContext.KerberosID;
customData.SiteminderToken = ClientContext.SiteminderToken;
CustomHeader header = new CustomHeader(customData);
// Add the custom header to the request.
request.Headers.Add(header);
return null;
}
/// <summary>
/// This method will be called after completion of a request to the server.
/// </summary>
/// <param name="reply"></param>
/// <param name="correlationState"></param>
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
#endregion
}
/// <summary>
/// This class will act as a custom context in the client side to hold the context information.
/// </summary>
public class ClientContext
{
public static string EmployeeID;
public static string WindowsLogonID;
public static string KerberosID;
public static string SiteminderToken;
}
/// <summary>
/// This custom behavior class is used to add both client and server inspectors to
/// the corresponding WCF end points.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class CustomBehavior : Attribute, IEndpointBehavior
{
#region IEndpointBehavior Members
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
return;
}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint,
System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
CustomMessageInspector inspector = new CustomMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint,
System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
ChannelDispatcher channelDispatcher = endpointDispatcher.ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher ed in channelDispatcher.Endpoints)
{
CustomMessageInspector inspector = new CustomMessageInspector();
ed.DispatchRuntime.MessageInspectors.Add(inspector);
}
}
}
void IEndpointBehavior.Validate(ServiceEndpoint endpoint) { return; }
#endregion
}
public class MyBehaviorExtensionElement : BehaviorExtensionElement
{
public MyBehaviorExtensionElement() { }
public override Type BehaviorType
{
get { return typeof(CustomBehavior); }
}
protected override object CreateBehavior()
{
return new CustomBehavior();
}
}
You need to add the extension to either your code or configuration: (config example below):
<extensions>
<behaviorExtensions>
<add name="yourMessageInspector"
type="MyBehaviorExtensionElement" />
</behaviorExtensions>
</extensions>
The following references should provide the background you need:
https://msdn.microsoft.com/en-us/library/ms730137%28v=vs.110%29.aspx
wcf :custom message inspector does not get wired up

ContentControl and static ressources

I try to extend my app with the missing CharacterEllipsis for TextBlocks in my Windows Phone 8 app. I found a nice solution here: http://nerdplusart.com/texttrimming-textblock-for-silverlight/.
So I implemented this in my code:
public class DynamicTextBlock : ContentControl
{
#region Text (DependencyProperty)
/// <summary>
/// Gets or sets the Text DependencyProperty. This is the text that will be displayed.
/// </summary>
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(DynamicTextBlock),
new PropertyMetadata(null, new PropertyChangedCallback(OnTextChanged)));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DynamicTextBlock)d).OnTextChanged(e);
}
protected virtual void OnTextChanged(DependencyPropertyChangedEventArgs e)
{
this.InvalidateMeasure();
}
#endregion
#region TextWrapping (DependencyProperty)
/// <summary>
/// Gets or sets the TextWrapping property. This corresponds to TextBlock.TextWrapping.
/// </summary>
public TextWrapping TextWrapping
{
get { return (TextWrapping)GetValue(TextWrappingProperty); }
set { SetValue(TextWrappingProperty, value); }
}
public static readonly DependencyProperty TextWrappingProperty =
DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(DynamicTextBlock),
new PropertyMetadata(TextWrapping.NoWrap, new PropertyChangedCallback(OnTextWrappingChanged)));
private static void OnTextWrappingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DynamicTextBlock)d).OnTextWrappingChanged(e);
}
protected virtual void OnTextWrappingChanged(DependencyPropertyChangedEventArgs e)
{
this.textBlock.TextWrapping = (TextWrapping)e.NewValue;
this.InvalidateMeasure();
}
#endregion
#region LineHeight (DependencyProperty)
/// <summary>
/// Gets or sets the LineHeight property. This property corresponds to TextBlock.LineHeight;
/// </summary>
public double LineHeight
{
get { return (double)GetValue(LineHeightProperty); }
set { SetValue(LineHeightProperty, value); }
}
public static readonly DependencyProperty LineHeightProperty =
DependencyProperty.Register("LineHeight", typeof(double), typeof(DynamicTextBlock),
new PropertyMetadata(0.0, new PropertyChangedCallback(OnLineHeightChanged)));
private static void OnLineHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DynamicTextBlock)d).OnLineHeightChanged(e);
}
protected virtual void OnLineHeightChanged(DependencyPropertyChangedEventArgs e)
{
textBlock.LineHeight = LineHeight;
this.InvalidateMeasure();
}
#endregion
#region LineStackingStrategy (DependencyProperty)
/// <summary>
/// Gets or sets the LineStackingStrategy DependencyProperty. This corresponds to TextBlock.LineStackingStrategy.
/// </summary>
public LineStackingStrategy LineStackingStrategy
{
get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); }
set { SetValue(LineStackingStrategyProperty, value); }
}
public static readonly DependencyProperty LineStackingStrategyProperty =
DependencyProperty.Register("LineStackingStrategy", typeof(LineStackingStrategy), typeof(DynamicTextBlock),
new PropertyMetadata(LineStackingStrategy.BlockLineHeight, new PropertyChangedCallback(OnLineStackingStrategyChanged)));
private static void OnLineStackingStrategyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DynamicTextBlock)d).OnLineStackingStrategyChanged(e);
}
protected virtual void OnLineStackingStrategyChanged(DependencyPropertyChangedEventArgs e)
{
this.textBlock.LineStackingStrategy = (LineStackingStrategy)e.NewValue;
this.InvalidateMeasure();
}
#endregion
/// <summary>
/// A TextBlock that gets set as the control's content and is ultiately the control
/// that displays our text
/// </summary>
private TextBlock textBlock;
/// <summary>
/// Initializes a new instance of the DynamicTextBlock class
/// </summary>
public DynamicTextBlock()
{
// create our textBlock and initialize
this.textBlock = new TextBlock();
this.Content = this.textBlock;
}
/// <summary>
/// Handles the measure part of the measure and arrange layout process. During this process
/// we measure the textBlock that we've created as content with increasingly smaller amounts
/// of text until we find text that fits.
/// </summary>
/// <param name="availableSize">the available size</param>
/// <returns>the base implementation of Measure</returns>
protected override Size MeasureOverride(Size availableSize)
{
// just to make the code easier to read
bool wrapping = this.TextWrapping == TextWrapping.Wrap;
Size unboundSize = wrapping ? new Size(availableSize.Width, double.PositiveInfinity) : new Size(double.PositiveInfinity, availableSize.Height);
string reducedText = this.Text;
// set the text and measure it to see if it fits without alteration
this.textBlock.Text = reducedText;
Size textSize = base.MeasureOverride(unboundSize);
while (wrapping ? textSize.Height > availableSize.Height : textSize.Width > availableSize.Width)
{
int prevLength = reducedText.Length;
reducedText = this.ReduceText(reducedText);
if (reducedText.Length == prevLength)
{
break;
}
this.textBlock.Text = reducedText + "...";
textSize = base.MeasureOverride(unboundSize);
}
return base.MeasureOverride(availableSize);
}
/// <summary>
/// Reduces the length of the text. Derived classes can override this to use different techniques
/// for reducing the text length.
/// </summary>
/// <param name="text">the original text</param>
/// <returns>the reduced length text</returns>
protected virtual string ReduceText(string text)
{
return text.Substring(0, text.Length - 1);
}
}
And in my XAML I use this like this:
<myNamespace:DynamicTextBlock Grid.Column="0" Text="Dies ist ein Text der sehr lang ist und umebrochen wird" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-1,0,0,0" Foreground="{Binding IsHighlighted, Converter={StaticResource BoolToBrushConverter}}" FontSize="32" />
Everything works cool. Now I want to apply a Style to this. But the following doesn´t work:
Style="{StaticResource PhoneTextLargeStyle}"
How the solution must be Extended to accept a StaticRessource as Style?
Styles in Windows Phone have a TargetType and they can only be set to controls of that type or its subtypes (child classes). PhoneTextLargeStyle's target is TextBlock, so you can't put it on other controls (like your DynamicTextBlock).
You would need to create a new style which targets DynamicTextBlock and sets the values that you like. I guess you can find out one way or another what the PhoneTextLargeStyle style does.

Ninject ActivationException

I'm getting the infamous "Error activating XYZ. No matching bindings are available blah blah blah" from Ninject 3.0.1.10 in an ASP.NET MVC project.
The following is how I've setup my binding (very simple):
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
string connectionString = WebConfigurationManager.ConnectionStrings["STAGING"].ConnectionString;
kernel.Bind<IUserAccountRepository>()
.To<SqlUserAccountRepository>()
.WithConstructorArgument("connectionString", connectionString);
kernel.Bind<IRecipeRepository>()
.To<SqlRecipeRepository>()
.WithConstructorArgument("connectionString", connectionString);
kernel.Bind<HomeViewModel>().ToSelf();
}
}
When the controller Index action is invoked it attempts to create a HomeViewModel object as such:
public ActionResult Index()
{
IKernel kernel = new StandardKernel();
HomeViewModel model = kernel.Get<HomeViewModel>();
...
Which triggers the exception:
Error activating IRecipeRepository No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IRecipeRepository into parameter recipeRepository of constructor of type HomeViewModel
1) Request for HomeViewModel
But if I attempt to get an instance of HomeViewModel directly after calling kernel.Bind in RegisterServices then it works fine.
Here's what the HomeViewModel looks like (some details removed for sake of brevity):
public class HomeViewModel
{
public HomeViewModel(IRecipeRepository recipeRepository,
IUserAccountRepository userAccountRepository)
{
this.recipeRepository = recipeRepository;
this.userAccountRepository = userAccountRepository;
}
//
// Some details removed for sake of brevity
//
private readonly IRecipeRepository recipeRepository;
private readonly IUserAccountRepository userAccountRepository;
}
Any idea what I'm missing? Why is the controller "special" in this case?