/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> private FindBindingResult FindControlCommandBinding(string[] path, string commandId, DotvvmControl viewRootControl, DotvvmControl targetControl, string validationTargetPath) { // walk the control tree and find the path ControlCommandBindingExpression resultBinding = null; DotvvmProperty resultProperty = null; DotvvmControl resultControl = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { // compare path if (ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { // find bindings of current control var binding = control.GetAllBindings().Where(p => p.Value is ControlCommandBindingExpression) .FirstOrDefault(b => b.Value.BindingId == commandId); if (binding.Key != null) { // verify that the target control is the control command target if (control.GetClosestControlBindingTarget() == targetControl) { // we have found the binding, now get the validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath == validationTargetPath) { // the validation path is equal, we have found the binding resultBinding = (ControlCommandBindingExpression)binding.Value; resultProperty = binding.Key; resultControl = control; } } } } }); return(new FindBindingResult { Property = resultProperty, Binding = resultBinding, Control = resultControl }); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> private FindBindingResult FindCommandBinding(string[] path, string commandId, DotvvmBindableObject viewRootControl, string validationTargetPath) { // walk the control tree and find the path CommandBindingExpression resultBinding = null; DotvvmBindableObject resultControl = null; DotvvmProperty resultProperty = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { // compare path if (resultBinding == null && ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { // find bindings of current control var binding = control.GetAllBindings() .FirstOrDefault(b => b.Value is CommandBindingExpression commandBinding && commandBinding.BindingId == commandId); if (binding.Key != null) { // we have found the binding, now get the validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath == validationTargetPath) { // the validation path is equal, we have found the binding resultBinding = (CommandBindingExpression)binding.Value; resultControl = control; resultProperty = binding.Key; } } } }); return(new FindBindingResult { Binding = resultBinding, Control = resultControl, Property = resultProperty }); }
public void Test() { var root = new StackPanel(); var c1 = new StackPanel(); var c2 = new StackPanel(); var c11 = new StackPanel(); var c12 = new StackPanel(); var c21 = new StackPanel(); var c22 = new StackPanel(); root.Add(c1); root.Add(c2); c1.Add(c11); c1.Add(c12); c2.Add(c21); c2.Add(c22); List <Control> directOrder = new List <Control>(); Control c = root; for (int i = 0; i < 8; i++, c = ControlTreeWalker.GetNextControl(c)) { directOrder.Add(c); } Assert.That(directOrder.ToArray(), Is.EqualTo(new Control[] { root, c1, c11, c12, c2, c21, c22, root })); List <Control> reverseOrder = new List <Control>(); c = root; for (int i = 0; i < 8; i++, c = ControlTreeWalker.GetPreviousControl(c)) { reverseOrder.Add(c); } Assert.That(reverseOrder.ToArray(), Is.EqualTo(new Control[] { root, c22, c21, c2, c12, c11, c1, root })); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> /// <param name="path">DataContext path of the binding</param> /// <param name="commandId">Id of the binding</param> /// <param name="viewRootControl">ViewRootControl of the binding</param> /// <param name="targetControl">Target control of the binding, null if not finding control command binding</param> /// <param name="validationTargetPath">Validation path of the binding</param> /// <param name="findControl">Determinate whether finding control command binding or not</param> /// <returns></returns> private FindBindingResult FindCommandBinding(string[] path, string commandId, DotvvmBindableObject viewRootControl, DotvvmBindableObject targetControl, string validationTargetPath, bool findControl) { // walk the control tree and find the path CommandBindingExpression resultBinding = null; DotvvmBindableObject resultControl = null; DotvvmProperty resultProperty = null; bool checkControl; bool bindingInPath = false; var candidateBindings = new Dictionary <string, CandidateBindings>(); string errorMessage = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { if (resultBinding == null) { // find bindings of current control var bindings = control.GetAllBindings() .Where(b => b.Value is CommandBindingExpression); foreach (var binding in bindings) { var wrongExceptionPropertyKeys = new List <string>(); var correctExceptionPropertyKeys = new List <string>(); var infoMessage = new StringBuilder(); // checking path if (!ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { wrongExceptionPropertyKeys.Add("DataContext path"); infoMessage.Append( $"Expected DataContext path: '{string.Join("/", path)}' Command binding DataContext path: '{string.Join("/", walker.CurrentPathArray)}'"); } else { //Found a binding in DataContext bindingInPath = true; correctExceptionPropertyKeys.Add("DataContext path"); } //checking binding id if (((CommandBindingExpression)binding.Value).BindingId != commandId) { wrongExceptionPropertyKeys.Add("binding id"); } else { correctExceptionPropertyKeys.Add("binding id"); } //checking validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath != validationTargetPath) { wrongExceptionPropertyKeys.Add("validation path"); infoMessage.Append($"Expected validation path: '{string.Join("/", validationTargetPath)}' Command binding validation path: '{string.Join("/", currentValidationTargetPath)}'"); } else { correctExceptionPropertyKeys.Add("validation path"); } //If finding control command binding checks if the binding is control otherwise always true checkControl = !findControl || control.GetClosestControlBindingTarget() == targetControl; if (!wrongExceptionPropertyKeys.Any() && checkControl) { //correct binding found resultBinding = (CommandBindingExpression)binding.Value; resultControl = control; resultProperty = binding.Key; } else if (wrongExceptionPropertyKeys.Any()) { var exceptionPropertyKey = (findControl && checkControl ? "Control command bindings with wrong " : "Command bindings with wrong ") + string.Join(", ", wrongExceptionPropertyKeys) + (correctExceptionPropertyKeys.Any() ? " and correct " + string.Join(", ", correctExceptionPropertyKeys) : "") + ":"; if (!candidateBindings.ContainsKey(exceptionPropertyKey)) { candidateBindings.Add(exceptionPropertyKey, new CandidateBindings()); } candidateBindings[exceptionPropertyKey] .AddBinding(new KeyValuePair <string, IBinding>(infoMessage.ToString(), binding.Value)); } else { errorMessage = "Invalid command invocation (the binding is not control command binding)"; } } } }); return(new FindBindingResult { ErrorMessage = bindingInPath ? errorMessage : "Nothing was found in found inside specified DataContext check if ViewModel is populated", CandidateBindings = candidateBindings, Binding = resultBinding, Control = resultControl, Property = resultProperty }); }