In my xamarin.forms App I am using material entry provided by xamarin.The control works fine. But how can I change the fontsize of placeholder?In ios the font size of placeholder is perfect, but in android it is much larger. And also the underline of the entry is little more in the left side.How to reduce the gap and align placeholder and underline equally(Refer Image)
What I Have done
What I am trying to achieve
My entry
<Entry x:Name="CustomerEntry" Visual="Material" FontSize="Small" Placeholder="Customer Name" HorizontalOptions="FillAndExpand" BackgroundColor="Transparent" TextColor="White" PlaceholderColor="White" Margin="0,0,0,0" ></Entry>
Any help is appreciated
For the font size, I believe that you'll need to custom render. See this answer for details on how to do that. Make sure to inherit from the Material Render.
To solve the left alignment issue, I couldn't find a good solution that worked for both Android and iOS, so what I did was to suck the left margin of the entry over and then use a box view to cover the underline so everything looks left aligned. I had do this in multiple places, so I created a custom control. The downside to this was passing all the bindings through.
My custom control Xaml:
<?xml version="1.0" encoding="UTF-8" ?>
<Grid x:Class="x.x.x.Controls.MaterialControls.MaterialEntry"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Name="MaterialEntryComponent"
Margin="-16,0,0,0"
Focused="OnComponentFocused">
<Entry x:Name="MaterialEntryEntry"
Grid.Row="0"
BackgroundColor="{Binding EntryBackgroundColor}"
BindingContext="{x:Reference MaterialEntryComponent}"
Completed="OnEntryCompleted"
FontFamily="{Binding FontFamily}"
FontSize="{Binding FontSize}"
IsPassword="{Binding IsPassword}"
IsSpellCheckEnabled="{Binding IsSpellCheckEnabled}"
IsTextPredictionEnabled="{Binding IsTextPredictionEnabled}"
Keyboard="{Binding Keyboard}"
MaxLength="{Binding MaxLength}"
Placeholder="{Binding Placeholder}"
PlaceholderColor="{Binding PlaceholderColor}"
ReturnType="{Binding ReturnType}"
Text="{Binding Text}"
TextChanged="OnEntryTextChanged"
TextColor="{Binding TextColor}"
Visual="Material" />
<BoxView Grid.Row="0"
Margin="{OnPlatform iOS='0,0,0,-1'}"
BackgroundColor="{Binding EntryBackgroundColor}"
BindingContext="{x:Reference MaterialEntryComponent}"
HorizontalOptions="Start"
VerticalOptions="FillAndExpand"
WidthRequest="16" />
</Grid>
The bulk of the work is being done by the negative left margin on the parent grid, and the width of 16 on the BoxView. I did find out I needed to move the margin of the BoxView down by 1 on iOS to cover the underline.
And the code behind:
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace x.x.x.Controls.MaterialControls
{
/// <summary>
/// Code behind for the Material Entry control.
/// </summary>
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MaterialEntry : Grid
{
#region Event Handlers
/// <summary>
/// Completed event. Fires when the return key on the keyboard is pressed.
/// </summary>
public event EventHandler Completed;
/// <summary>
/// Text changed event. Fires when the text on the entry control is changed.
/// </summary>
public event EventHandler<TextChangedEventArgs> TextChanged;
#endregion
#region Bindable Properties
/// <summary>
/// Bindable property for the entry background color on the view.
/// </summary>
public static readonly BindableProperty EntryBackgroundColorProperty =
BindableProperty.Create(nameof(EntryBackgroundColor), typeof(Color), typeof(MaterialEntry), Color.White);
/// <summary>
/// Bindable property for the font family of the entry on the view..
/// </summary>
public static readonly BindableProperty FontFamilyProperty =
BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(MaterialEntry), default(string));
/// <summary>
/// Bindable property for the font size of the entry on the view..
/// </summary>
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(nameof(FontSize), typeof(double), typeof(MaterialEntry), 12.0);
/// <summary>
/// Bindable property for the IsPassword of the entry on the view.
/// </summary>
public static readonly BindableProperty IsPasswordProperty =
BindableProperty.Create(nameof(IsPassword), typeof(bool), typeof(MaterialEntry), false);
/// <summary>
/// Bindable property for the IsSpellCheckEnabled of the entry on the view.
/// </summary>
public static readonly BindableProperty IsSpellCheckEnabledProperty =
BindableProperty.Create(nameof(IsSpellCheckEnabled), typeof(bool), typeof(MaterialEntry), true);
/// <summary>
/// Bindable property for the IsTextPredictionEnabled of the entry on the view.
/// </summary>
public static readonly BindableProperty IsTextPredictionEnabledProperty =
BindableProperty.Create(nameof(IsTextPredictionEnabled), typeof(bool), typeof(MaterialEntry), true);
/// <summary>
/// Bindable property for the keyboard type of the entry on the view.
/// </summary>
public static readonly BindableProperty KeyboardProperty =
BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(MaterialEntry), Keyboard.Default);
/// <summary>
/// Bindable property for the MaxLength of the entry on the view..
/// </summary>
public static readonly BindableProperty MaxLengthProperty =
BindableProperty.Create(nameof(MaxLength), typeof(int), typeof(MaterialEntry), int.MaxValue);
/// <summary>
/// Bindable property for the placeholder text of the entry on the view.
/// </summary>
public static readonly BindableProperty PlaceholderProperty =
BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(MaterialEntry), default(string));
/// <summary>
/// Bindable property for the placeholder text color of the entry on the view.
/// </summary>
public static readonly BindableProperty PlaceholderColorProperty =
BindableProperty.Create(nameof(PlaceholderColor), typeof(Color), typeof(MaterialEntry), Color.Black);
/// <summary>
/// Bindable property for the return command of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnCommandProperty =
BindableProperty.Create(nameof(ReturnCommand), typeof(ICommand), typeof(Entry), default(ICommand));
/// <summary>
/// Bindable property for the return command parameter of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnCommandParameterProperty =
BindableProperty.Create(nameof(ReturnCommandParameter), typeof(object), typeof(Entry), default(object));
/// <summary>
/// Bindable property for the return type of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnTypeProperty =
BindableProperty.Create(nameof(ReturnType), typeof(ReturnType), typeof(Entry), ReturnType.Default);
/// <summary>
/// Bindable property for the text of the entry on the view.
/// </summary>
public static readonly BindableProperty TextProperty =
BindableProperty.Create(nameof(Text), typeof(string), typeof(MaterialEntry), default(string), BindingMode.TwoWay);
/// <summary>
/// Bindable property for the text color of the entry on the view.
/// </summary>
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(MaterialEntry), Color.Black);
#endregion
#region Properties
/// <summary>
/// The background color of the entry control. Default is <see cref="Color.White"/>.
/// </summary>
public Color EntryBackgroundColor
{
get => (Color)GetValue(EntryBackgroundColorProperty);
set => SetValue(EntryBackgroundColorProperty, value);
}
/// <summary>
/// The font family for the entry control to use.
/// </summary>
public string FontFamily
{
get => (string)GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
/// <summary>
/// The font size of the entry control. Default is 12.0.
/// </summary>
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
get => (double)GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
/// <summary>
/// Set if the entry field is a password field. Default is false.
/// </summary>
public bool IsPassword
{
get => (bool)GetValue(IsPasswordProperty);
set => SetValue(IsPasswordProperty, value);
}
/// <summary>
/// Set if spell check is enabled on the entry. Default is True.
/// </summary>
public bool IsSpellCheckEnabled
{
get => (bool)GetValue(IsSpellCheckEnabledProperty);
set => SetValue(IsSpellCheckEnabledProperty, value);
}
/// <summary>
/// Set if text prediction is enabled on the entry. Default is True.
/// </summary>
public bool IsTextPredictionEnabled
{
get => (bool)GetValue(IsTextPredictionEnabledProperty);
set => SetValue(IsTextPredictionEnabledProperty, value);
}
/// <summary>
/// The type of keyboard to use for the entry control. Default is <see cref="Keyboard.Default"/>.
/// </summary>
public Keyboard Keyboard
{
get => (Keyboard)GetValue(KeyboardProperty);
set => SetValue(KeyboardProperty, value);
}
/// <summary>
/// The maximum allowed length of input for the entry. Default is <see cref="int.MaxValue"/>.
/// </summary>
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
/// <summary>
/// The text to use for the placeholder.
/// </summary>
public string Placeholder
{
get => (string)GetValue(PlaceholderProperty);
set => SetValue(PlaceholderProperty, value);
}
/// <summary>
/// The color of the placeholder text. Default is <see cref="Color.Black"/>.
/// </summary>
public Color PlaceholderColor
{
get => (Color)GetValue(PlaceholderColorProperty);
set => SetValue(PlaceholderColorProperty, value);
}
/// <summary>
/// The command that fires when the return button on the keyboard is tapped.
/// </summary>
public ICommand ReturnCommand
{
get => (ICommand)GetValue(ReturnCommandProperty);
set => SetValue(ReturnCommandProperty, value);
}
/// <summary>
/// The parameter to pass with the return command.
/// </summary>
public object ReturnCommandParameter
{
get => GetValue(ReturnCommandParameterProperty);
set => SetValue(ReturnCommandParameterProperty, value);
}
/// <summary>
/// The type of return button to display on the keyboard. Default is <see cref="ReturnType.Default"/>.
/// </summary>
public ReturnType ReturnType
{
get => (ReturnType)GetValue(ReturnTypeProperty);
set => SetValue(ReturnTypeProperty, value);
}
/// <summary>
/// The text of the entry.
/// </summary>
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
/// <summary>
/// The color of the text. Default is <see cref="Color.Black"/>.
/// </summary>
public Color TextColor
{
get => (Color)GetValue(TextColorProperty);
set => SetValue(TextColorProperty, value);
}
#endregion
/// <summary>
/// Constructor.
/// </summary>
public MaterialEntry()
{
InitializeComponent();
}
#region Methods
/// <summary>
/// Focuses the entry control.
/// </summary>
public void FocusEntry()
{
MaterialEntryEntry.Focus();
}
private void OnEntryCompleted(object sender, EventArgs e)
{
SendCompleted();
}
private void OnEntryTextChanged(object sender, TextChangedEventArgs e)
{
TextChanged?.Invoke(this, e);
}
private void SendCompleted()
{
if (IsEnabled)
{
Completed?.Invoke(this, EventArgs.Empty);
if (ReturnCommand != null && ReturnCommand.CanExecute(ReturnCommandParameter))
{
ReturnCommand.Execute(ReturnCommandParameter);
}
}
}
private void OnComponentFocused(object sender, FocusEventArgs e)
{
FocusEntry();
}
#endregion
}
}
To use the control, remember to import the namespace it into your view with:
xmlns:material="clr-namespace:x.x.x.Controls.MaterialControls".
Then using it would be something like:
<material:MaterialEntry Placeholder="Do something amazing"
Style="{StaticResource EntryStyle}"
Text="{Binding MyEntryText}" />
Related
I have a custom renderer for a Xamarin entry and I have added this.Control.VerticalScrollBarEnabled = true; inside of the OnElementChanged inside of the android renderer but I can not see a scroll bar.
I have done similar on the iOS side this.Control.ScrollEnabled = true; and it works.
Am I missing something? thank you
Android Custom renderer code
using Android.Content;
using Android.Graphics.Drawables;
using NGT.Views.ReusableViews;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(BorderedEditor), typeof(NGT.Droid.BorderedEditorRenderer))]
namespace NGT.Droid
{
/// <summary>
/// Boardered editor renderer.
/// </summary>
public class BorderedEditorRenderer : EditorRenderer
{
/// <summary>
/// Initializes a new instance of the <see cref="BorderedEditorRenderer"/> class.
/// </summary>
/// <param name="context">Context.</param>
public BorderedEditorRenderer(Context context)
: base(context)
{
}
/// <summary>
/// Ons the element changed.
/// </summary>
/// <param name="e">E.</param>
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
this.Control.VerticalScrollBarEnabled = true;
}
if (e.OldElement == null)
{
GradientDrawable gd = new GradientDrawable();
gd.SetCornerRadius(5);
gd.SetStroke(2, Constants.AppBlue.ToAndroid());
this.Control.Background = gd;
this.Control.ImeOptions = Android.Views.InputMethods.ImeAction.Done;
}
}
}
} ```
When I create LibVLC and MediaPlayer objects in the constructor and play the video, there is only sound but no image. When I create LibVLC and MediaPlayer objects in the'Play' function, there are sounds and images. I don't want to create a MediaPlayer object every time the play function is called. what should I do?
using System;
using System.ComponentModel;
using System.Windows.Input;
using LibVLCSharp.Shared;
using static Xamarin.Essentials.Permissions;
namespace MediaElement
{
/// <summary>
/// Represents the main viewmodel.
/// </summary>
public class MainViewModel : INotifyPropertyChanged
{
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Initializes a new instance of <see cref="MainViewModel"/> class.
/// </summary>
public MainViewModel()
{
Core.Initialize();
LibVLC = new LibVLC();
MediaPlayer = new MediaPlayer(LibVLC) { EnableHardwareDecoding = true };
}
private LibVLC _libVLC;
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.LibVLC"/> instance.
/// </summary>
public LibVLC LibVLC
{
get => _libVLC;
private set => Set(nameof(LibVLC), ref _libVLC, value);
}
private MediaPlayer _mediaPlayer;
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.MediaPlayer"/> instance.
/// </summary>
public MediaPlayer MediaPlayer
{
get => _mediaPlayer;
private set => Set(nameof(MediaPlayer), ref _mediaPlayer, value);
}
/// <summary>
/// Initialize LibVLC and playback when page appears
/// </summary>
public void Play(String path)
{
MediaPlayer.Play(new LibVLCSharp.Shared.Media(LibVLC, new Uri(path)));
}
private void Set<T>(string propertyName, ref T field, T value)
{
if (field == null && value != null || field != null && !field.Equals(value))
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
You only sent half of your code, we don't know how you are using your VideoView control.
As a general rule of thumb:
How do you attach the MediaPlayer to your view?
Do you properly wait for the view to be visible before calling Play?
Have a look at the samples here and compare to see what you did wrong.
How can I change between UserControls in the View, based on a property of the ViewModel, in a Windows 8 store app?
Say my ViewModel has a property which looks something like this:
class MyViewModel
{
public string CurrentStatus
{
get { return (string)GetValue(CurrentStatusProperty); }
set { SetValue(CurrentStatusProperty, value); }
}
public static readonly DependencyProperty CurrentStatusProperty =
DependencyProperty.Register("CurrentStatus", typeof(string), typeof(MyViewModel), new PropertyMetadata("default", CurrentStatusChanged));
...
}
How do I make my View change an UserControl according to the value of the CurrentStatus from the ViewModel?
The strightforward solution for me would have been to create a binding between the CurrentStatus from the ViewModel and another string from the View, but apparently data binding can only be used for a DependencyObject (which a string isn't).
Edit:
The xaml file contains just a StackPanel in which I want to put a UserControl, based on the CurrentStatus. So, if the CurrentStatus is "one" I want the StackPanel to contain UserControlOne and so on...
Any ideas or nice solutions to this problem?
Thanks a lot!
I usually use a ContentControl and set it's ContentTemplate based on a DataTrigger
I have an example in my blog post Switching between Views/UserControls using MVVM, but here's a sample of what that may look like using your scenario:
<DataTemplate x:Key="DefaultTemplate">
<local:DefaultUserControl />
</DataTemplate>
<DataTemplate x:Key="ClosedTemplate">
<local:ClosedUserControl />
</DataTemplate>
<Style x:Key="MyContentControlStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentStatus}" Value="Closed">
<Setter Property="ContentTemplate" Value="{StaticResource ClosedTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
...
<ContentControl Style="{StaticResource MyContentControlStyle}" />
EDIT
Apparently DataTriggers are not supported in WinRT, and have been replaced with the VisualStateManager. I haven't had the chance to use this yet, however from what I'm reading they used the same approach for WinRT as they did Silverlight (which also didn't support DataTriggers until v5), and my solution for Silverlight was to use a DataTemplateSelector
I hope that can point you in the right direction :)
Not sure I fully understand what you are trying to do. Can you post the xaml?
If what you are wanting is to present the controls differently based on the status, then use a converter and you can present a different template based upon the status:
public class StatusToTemplateConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((string) value)
{
case "Status1":
return Application.Current.Resources["Status1Template"];
case "Status2":
return Application.Current.Resources["Status2Template"];
default:
return Application.Current.Resources["Status3Template"];
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
#endregion
}
the above assumes you have your templates defined in a resource file
If all you ae wanting to do is something simpler such as red text for Status1 or Green text for status2 you could have a converter that just converts the status to a colour and bind the FontColor to the status and use the converter.
But like I said, without more code being posted, I'm not 100% clear on what you are trying to achieve
While I've used the DataTemplateSelector and IValueConverter in such cases before - now my favorite approach is using the VisualStateManager. I have created a most basic attached property that implements the attached behavior pattern in WinRT XAML Toolkit here - that looks like this:
/// <summary>
/// Defines an attached property that controls the visual state of the element based on the value.
/// </summary>
public static class VisualStateExtensions
{
#region State
/// <summary>
/// State Attached Dependency Property
/// </summary>
public static readonly DependencyProperty StateProperty =
DependencyProperty.RegisterAttached(
"State",
typeof(string),
typeof(VisualStateExtensions),
new PropertyMetadata(null, OnStateChanged));
/// <summary>
/// Gets the State property. This dependency property
/// indicates the VisualState that the associated control should be set to.
/// </summary>
public static string GetState(DependencyObject d)
{
return (string)d.GetValue(StateProperty);
}
/// <summary>
/// Sets the State property. This dependency property
/// indicates the VisualState that the associated control should be set to.
/// </summary>
public static void SetState(DependencyObject d, string value)
{
d.SetValue(StateProperty, value);
}
/// <summary>
/// Handles changes to the State property.
/// </summary>
/// <param name="d">
/// The <see cref="DependencyObject"/> on which
/// the property has changed value.
/// </param>
/// <param name="e">
/// Event data that is issued by any event that
/// tracks changes to the effective value of this property.
/// </param>
private static void OnStateChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var stateName = (string)e.NewValue;
var ctrl = (Control)d;
VisualStateManager.GoToState(ctrl, stateName, true);
}
#endregion
}
You should define an enum-style class like the VisualStates class in Silverlight Toolkit that lists all your visual states (so you don't have duplicates), e.g.
internal static class VisualStates
{
#region GroupCommon
/// <summary>
/// Common state group.
/// </summary>
public const string GroupCommon = "CommonStates";
/// <summary>
/// Normal state of the Common state group.
/// </summary>
public const string StateNormal = "Normal";
/// <summary>
/// Normal state of the Common state group.
/// </summary>
public const string StateReadOnly = "ReadOnly";
/// <summary>
/// MouseOver state of the Common state group.
/// </summary>
public const string StateMouseOver = "MouseOver";
/// <summary>
/// Pressed state of the Common state group.
/// </summary>
public const string StatePressed = "Pressed";
/// <summary>
/// Disabled state of the Common state group.
/// </summary>
public const string StateDisabled = "Disabled";
#endregion GroupCommon
#region GroupFocus
/// <summary>
/// Focus state group.
/// </summary>
public const string GroupFocus = "FocusStates";
/// <summary>
/// Unfocused state of the Focus state group.
/// </summary>
public const string StateUnfocused = "Unfocused";
/// <summary>
/// Focused state of the Focus state group.
/// </summary>
public const string StateFocused = "Focused";
#endregion GroupFocus
}
Once you have these - you can have a property in your view model like
public string VisualState { get; set; /* Raise PropertyChange event your preferred way here */ }
And in your view say
<Page
...
xmlns:extensions="using:WinRTXamlToolkit.Controls.Extensions"
extensions:VisualStateExtensions.State="{Binding VisualState}">...
Then your view model can easily drive the change of the visual state and you can use Blend to define what that state looks like - e.g. change the Content or ContentTemplate or simply visibility of various elements in the layout. I think this method has best support of the designer tools since you can flip between views with a click of a button and make updates to these views in Blend.
When a page loads I start a new task in my hub. This task sends data to a browser updating a certain html elements. When I browse away from the page I want to stop the task.
The problem is that before the task is stopped (due to it's sleep argument), a new tokenSource = new CancellationTokenSource();
is set before the previous instance of this task had a chance to stop.
What i'm trying to do is to have the task stop when browsing away from the page to a different page that is not requiring signalR. BUT maybe, not stop it if it's only a refresh of the same page. Not sure how to do it. To sum it up, I want to guarantee that only 1 instance of this task is running (AND only on the page that requires it/or have a listener)
any info greatly appreciated.
thanks
CODE:
public class TaskActionStatus : Hub
{
#region Static Fields
/// <summary>
/// The token source.
/// </summary>
private static CancellationTokenSource tokenSource;
/// <summary>
/// The url string.
/// </summary>
private static string url = string.Empty;
#endregion
#region Public Methods and Operators
/// <summary>
/// The get tasks status.
/// </summary>
/// <param name="siteId">
/// The site id.
/// </param>
/// <param name="location"></param>
public void GetTasksStatus(int? siteId)
{
var taskRepository = UnityContainerSetup.Container.Resolve<ITaskRepository>();
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
// init task for checking task statuses
var tasksItem = new DownloadTaskItem();
// start task only if at least one listener
if (UserHandler.ConnectedIds.Count < 2 && !taskRepository.IsTasksStatusAsyncRunning())
{
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
else tokenSource.Cancel();
}
/// <summary>
/// The on connected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(this.Context.ConnectionId);
return base.OnConnected();
}
/// <summary>
/// The on disconnected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnDisconnected()
{
UserHandler.ConnectedIds.Remove(this.Context.ConnectionId);
if (UserHandler.ConnectedIds.Count == 0)
{
try
{
tokenSource.Cancel();
}
catch (Exception ex)
{
Log.Error(ex);
}
}
return base.OnDisconnected();
}
/// <summary>
/// The update tasks status.
/// </summary>
/// <param name="sender">
/// The sender.
/// </param>
/// <param name="e">
/// The e.
/// </param>
public void UpdateTasksStatus(object sender, TaskEventArgs e)
{
this.Clients.All.updateMessages(e.Tasks);
}
#endregion
}
/// <summary>
/// The user handler.
/// </summary>
public static class UserHandler
{
#region Static Fields
/// <summary>
/// The connected ids.
/// </summary>
public static HashSet<string> ConnectedIds = new HashSet<string>();
#endregion
}
public bool IsTasksStatusAsyncRunning()
{
if (tasksStatusAsync != null && tasksStatusAsync.Status.Equals(TaskStatus.Running))
{
return true;
}
return false;
}
Moving this line:
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
...
making it this:
if (UserHandler.ConnectedIds.Count < 2)
{
Trace.WriteLine("GetTasksStatus: Starting new task");
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
did it for me. thanks
I want to perform some simple form validation in my controller.
Here's an excerpt from the controller action:
// other code
if (!string.IsNullOrEmpty(editModel.NewPassword)
&& editModel.RepeatNewPassword != editModel.NewPassword) {
// problem line... How to I get the key from editModel?
ModelState.AddModelError("", "The new password does not match the repeated password.")
}
// other code
It appears that must use a string as the error's key. Is there a way i can generate the corect key from the model, or should I just check for what input name Html.PasswordFor(x => x.NewPassword) returns?
Or in your ViewModel you can do this
public class ClassName
{
public string Password { get; set; }
[Compare("Password" , "Password Must Match")]
public string ConfirmPassword { get; set; }
}
this is new to mvc3 and you can implement your custom attribute like this fairly easy in mvc3
because IsValid now recives a ValidationContext parameter which contains information about the validation that is being performed like the type of the model and metadata associated with it so you can use reflection to get other properties and their value the CompareAttribute made use of this feature
Not exactly what you are asking for, but will solve your problem:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute
{
#region [ Fields ]
/// <summary>
/// Defines the default error messsage
/// </summary>
private const string DefaultErrorMessage = "'{0}' and '{1}' do not match.";
/// <summary>
/// Defines a typeId
/// </summary>
private readonly object typeId = new object();
#endregion
#region [ Constructors ]
/// <summary>
/// Initializes a new instance of the PropertiesMustMatchAttribute class.
/// </summary>
/// <param name="originalProperty">The original property name</param>
/// <param name="confirmProperty">The confirm (or match) property name</param>
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(DefaultErrorMessage)
{
this.OriginalProperty = originalProperty;
this.ConfirmProperty = confirmProperty;
}
#endregion
#region [ Properties ]
/// <summary>
/// Gets the confirm property name
/// </summary>
public string ConfirmProperty { get; private set; }
/// <summary>
/// Gets the original property name
/// </summary>
public string OriginalProperty { get; private set; }
/// <summary>
/// Gets a unique identifier for this <see cref="T:System.Attribute"/>.
/// </summary>
/// <returns>An <see cref="T:System.Object"/> that is a unique identifier for the attribute.</returns>
/// <filterpriority>2</filterpriority>
public override object TypeId
{
get
{
return this.typeId;
}
}
#endregion
#region [ Overrides ]
/// <summary>
/// Applies formatting to an error message, based on the data field where the error occurred.
/// </summary>
/// <returns>An instance of the formatted error message.</returns>
/// <param name="name">The name to include in the formatted message.</param>
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, this.OriginalProperty, this.ConfirmProperty);
}
/// <summary>
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <returns>true if the specified value is valid; otherwise, false.</returns>
/// <param name="value">The value of the object to validate. </param>
public override bool IsValid(object value)
{
var properties = TypeDescriptor.GetProperties(value);
var originalValue = properties.Find(this.OriginalProperty, true /* ignoreCase */).GetValue(value);
var confirmValue = properties.Find(this.ConfirmProperty, true /* ignoreCase */).GetValue(value);
return Equals(originalValue, confirmValue);
}
#endregion
}
And then:
[PropertiesMustMatch("NewPassword", "RepeatNewPassword ", ErrorMessage = "The new password and confirmation password do not match.")]
public class YourModel
{
public string NewPassword {get;set;}
public string RepeatNewPassword {get;set;}
}