Issue
I have behavior for entry completed command, that validates data inside of entry, logic for that i keep in ViewModel. But also, when i complete entry i need to change the focus to the next entry (next entry does not have a x:Name, because it is inside of the DataTemplate). To change focus i need object of the next entry, and i finding that object via his parent right in the Behavior file, not in VM. It is correctly way to do this in MVVM, or i should pass entry object via parameter to VM and find his parent and then next entry in VM?
Behavior:
using System.Windows.Input;
using Xamarin.Forms;
namespace RollPositioningMobile.ViewModels.Behaviors
{
public class EntryCompletedBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
bindable.Completed += Bindable_Completed;
}
protected override void OnDetachingFrom(Entry bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
bindable.Completed -= Bindable_Completed;
AssociatedObject = null;
}
private void Bindable_BindingContextChanged(object sender, System.EventArgs e)
{
OnBindingContextChanged();
}
private void Bindable_Completed(object sender, System.EventArgs e)
{
if (Command == null) return;
Entry entry = (Entry)sender;
Grid circularEntriesGrid;
//If this handler was invoked from the RequiredValueEntry,
//focus on the next Entry mechanic is different
if (entry.TabIndex == 0)
{
//First we need to define the main Grid,
//and then find subgrid inside of the main
Grid mainGrid = (Grid)entry.Parent.Parent;
circularEntriesGrid = mainGrid.FindByName<Grid>("CircularEntriesGrid");
}
else
{
//Get the Frame parent and then the Grid parent of the Entry
circularEntriesGrid = (Grid)entry.Parent.Parent;
//Check for last entry
if (circularEntriesGrid.Children.Count == entry.TabIndex)
return;
}
//Execution of the input data validation commands
if (Command.CanExecute(entry.TabIndex))
Command.Execute(entry.TabIndex);
//Set focus on the next Entry
if ((bool)CommandParameter)
{
var nextEntryFrame = (Frame)circularEntriesGrid.Children[entry.TabIndex];
var nextEntry = (Entry)nextEntryFrame.Content;
nextEntry.Focus();
}
else
{
entry.Focus();
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
public Entry AssociatedObject { get; private set; }
public static readonly BindableProperty CommandProperty =
BindableProperty.Create("Command", typeof(ICommand), typeof(EntryCompletedBehavior), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create("CommandParameter", typeof(object), typeof(EntryCompletedBehavior), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
}
}
VM part:
public ICommand EntryCompletedCommand { get; protected set; }
void EntryCompleted(object param)
{
var entryId = (int)param;
//Validating required value
if (entryId == 0)
{
RequiredValueIsValid = true;
if (RequiredValue <= 0)
{
Application.Current.MainPage.DisplayAlert("Error", $"Required value cannot be equals to {RequiredValue}", "OK");
RequiredValueIsValid = false;
}
return;
}
//Validating actual values
var entry = ActualValues[entryId - 1];
var value = entry.Value;
if (value < 0 || Math.Abs(value - RequiredValue) > Measurment.MaxOffset)
{
entry.Value = entry.OldValue;
Application.Current.MainPage.DisplayAlert("Error", $"The actual and the required value should not differ more than {Measurment.MaxOffset}", "OK");
entry.IsValid = false;
return;
}
entry.IsValid = true;
RequiredValueIsValid = true;
entry.OldValue = entry.Value;
}
Solution
Can i implement logic code in behavior or should i put it whole to binded command in VM?
Since you had used MVVM , it would better to handle the logic in ViewModel . We always do some customization of the element itself .
In your case , it is necessary to pass the entry as params to ViewModel . You could binding the value of IsFocused to the property of Model and handle it directly in VM .
Here is a similar thread and I had provided a whole solution .Hope it will be helpful to you .
Answered By - Lucas Zhang - MSFT
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.