public void NestedCollectionAbsolutePathTest() { /*Arrange*/ //create a parent binding. /*Arrange*/ Binding.BindingDef parent = new Binding.BindingDef(new WebformControl(new TextBox()), "", new Options { Path = "" }, controlService); string rawPath = "ViewModelID"; BindingPath path = new BindingPath(rawPath, parent.SourceExpression, PathMode.Absolute); var viewModel = new { ViewModelID = "viewmodel1" }; /*Act*/ SourceProperty sourceProperty = path.ResolveAsSource(viewModel); /*Assert*/ Assert.IsNotNull(sourceProperty); Assert.IsNotNull(sourceProperty.Descriptor); Assert.IsNotNull(sourceProperty.OwningInstance); Assert.IsNotNull(sourceProperty.Value); Assert.AreEqual("ViewModelID", sourceProperty.Descriptor.Name); Assert.AreEqual(viewModel, sourceProperty.OwningInstance); Assert.AreEqual(viewModel.ViewModelID, sourceProperty.Value); }
public void VerifyTextboxTextProgrammaticBindCreatesCorrectBindingObject() { /*Arrange*/ //We expect at least one call this.viewModel.Expect(vm => vm.EmployeeName).Return("Sam Shiles").Repeat.Once(); TextBox tb = new TextBox(); Options options = new Options { Path = "EmployeeName" }; /*Act*/ object resolvedValue = this.binder.ExecuteBind(new WebformControl(tb), options, "Text"); /*Assert*/ //Assert on the binding collection to make sure that the binding has been created successfully Assert.IsNotNull(collection); Assert.AreEqual(1, collection.Count); Binding.BindingDef binding = this.collection[0]; //Assert the options have been stored on the binding correctly Assert.AreEqual(binding.BindingOptions, options); Assert.IsTrue(!binding.IsSourceEnumerable); //Assert that control service has been passed to the binding Assert.IsNotNull(binding.ControlService); Assert.AreEqual(this.controlService, binding.ControlService); //Assert that the binding has created target and source expression objects Assert.IsNotNull(binding.SourceExpression); Assert.IsNotNull(binding.TargetExpression); Assert.IsFalse(binding.HasValueConverter); }
/// <summary> /// Bind to a command when the TargetProperty is known /// </summary> /// <param name="control"></param> /// <param name="bindingOptions"></param> /// <param name="targetPropertyName"></param> public void ExecuteCommandBind(IBindingTarget control, Options bindingOptions, string targetPropertyName) { BindingDef binding = new BindingDef(control, targetPropertyName, bindingOptions, controlService); CommandStorage.Add(binding); ExecuteCommandBind(control, binding); }
private object AttemptConvert(BindingDef binding, object value, IBindingTarget container) { if (binding.HasValueConverter) { IValueConverter converter = binding.GetValueConverterInstance(); value = converter.Convert(value, binding.ResolveAsTarget(container).Descriptor.PropertyType, binding, CultureInfo.CurrentCulture); } return(value); }
private void ApplyBinding(BindingDef binding, IBindingContainer bindingContainer) { TargetProperty property = binding.ResolveAsTarget(this.bindingContainer); if (property != null) { object value = property.Value; SetProperty(binding, value); } }
private bool TrySetParent(BindingDef lastBinding) { if (lastBinding != null) { //test if the current binding is a child of the previous datacontainer IBindingTarget child = controlService.FindControlUnique(lastBinding.Container, this.Container.UniqueID); if (child != null) { this.Parent = lastBinding; } else if (lastBinding.Parent != null) { TrySetParent(lastBinding.Parent); } } return(this.Parent != null); }
public void VerifyRepeaterProgrammaticBindCreatesCorrectBindingObject() { /*Arrange*/ List <Child> children = new List <Child> { new Child { Name = "Ben" }, new Child { Name = "Sam" }, new Child { Name = "Dave" }, new Child { Name = "Ali" } }; this.viewModel.Expect(vm => vm.ChildrensNames).Return(children).Repeat.Once(); Repeater rpt = new Repeater(); Options options = new Options { Path = "ChildrensNames" }; /*Act*/ object resolvedValue = this.binder.ExecuteBind(new WebformControl(rpt), options, "DataSource"); /*Assert*/ Assert.AreEqual(children, resolvedValue); Binding.BindingDef binding = this.collection[0]; Assert.IsTrue(binding.IsSourceEnumerable); //collection bindings should always be oneway. Assert.AreEqual(BindingMode.OneWay, binding.BindingOptions.Mode); //Assert that control service has been passed to the binding Assert.IsNotNull(binding.ControlService); Assert.AreEqual(this.controlService, binding.ControlService); //Assert that the binding has created target and source expression objects Assert.IsNotNull(binding.SourceExpression); Assert.IsNotNull(binding.TargetExpression); Assert.IsFalse(binding.HasValueConverter); }
//TODO: Should probably be a member of binding. private void SetProperty(BindingDef binding, object value) { SourceProperty property = binding.SourceExpression.ResolveAsSource(this.DataContext); if (property != null && property.Descriptor != null && !property.Descriptor.IsReadOnly) { object convertedValue = null; Type destinationType = property.Descriptor.PropertyType; if (binding.HasValueConverter) { IValueConverter valueConverter = binding.GetValueConverterInstance(); convertedValue = valueConverter.ConvertBack(value, property.Descriptor.PropertyType, null, null); } else { if (TypeHelper.IsSimpleType(value.GetType()) && TypeHelper.IsSimpleType(destinationType)) { convertedValue = Convert.ChangeType(value, destinationType); } else { TypeConverter converter = TypeDescriptor.GetConverter(destinationType); if (converter != null) { convertedValue = converter.ConvertFrom(value); } else { converter = TypeDescriptor.GetConverter(value.GetType()); if (converter != null) { convertedValue = converter.ConvertTo(value, destinationType); } } } } property.Descriptor.SetValue(property.OwningInstance, convertedValue); } }
public void NestedAbsolutePathTest() { /*Arrange*/ //create a parent binding. Binding.BindingDef parent = new Binding.BindingDef( new WebformControl(new TextBox()) , "Text", 0 , new BindingCollection() , new Options { Path = "Companies" } , true, controlService); string rawPath = "CompanyName"; BindingPath path = new BindingPath(rawPath, parent.SourceExpression, PathMode.Absolute); var employee1 = new { Name = "Sam" }; var employee2 = new { Name = "Ben" }; var employee3 = new { Name = "Ali" }; var list = new[] { employee1, employee2, employee3 }; var company = new { AvailableEmployees = list }; var companyList = new[] { company }; var viewModel = new { CompanyName = "Tesco Ltd.", Companies = companyList }; /*Act*/ SourceProperty sourceProperty = path.ResolveAsSource(viewModel); /*Assert*/ Assert.IsNotNull(sourceProperty); Assert.IsNotNull(sourceProperty.Descriptor); Assert.IsNotNull(sourceProperty.OwningInstance); Assert.IsNotNull(sourceProperty.Value); Assert.AreEqual("CompanyName", sourceProperty.Descriptor.Name); Assert.AreEqual(viewModel, sourceProperty.OwningInstance); Assert.AreEqual(viewModel.CompanyName, sourceProperty.Value); }
public void NestedRelativePathTest() { /*Arrange*/ Binding.BindingDef parent = new Binding.BindingDef( new WebformControl(new TextBox()), "Text", new Options() { Path = "Company" }, controlService); string rawPath = "AvailableEmployees.Name"; BindingPath path = new BindingPath(rawPath, 2, parent.SourceExpression, PathMode.Relative); var employee1 = new { Name = "Sam" }; var employee2 = new { Name = "Ben" }; var employee3 = new { Name = "Ali" }; var list = new[] { employee1, employee2, employee3 }; var company = new { AvailableEmployees = list }; var viewModel = new { Company = company }; /*Act*/ SourceProperty sourceProperty = path.ResolveAsSource(viewModel); /*Assert*/ Assert.IsNotNull(sourceProperty); Assert.IsNotNull(sourceProperty.Descriptor); Assert.IsNotNull(sourceProperty.OwningInstance); Assert.IsNotNull(sourceProperty.Value); Assert.AreEqual("Ali", sourceProperty.Value); Assert.AreEqual("Name", sourceProperty.Descriptor.Name); //empoyee at the index of 1 Assert.AreEqual(employee3, sourceProperty.OwningInstance); Assert.AreEqual(employee3.Name, sourceProperty.Value); Assert.AreEqual("Name", sourceProperty.Descriptor.Name); }
private void ExecuteCommandBind(IBindingTarget control, BindingDef binding) { //Get the ICommandObject from the source SourceProperty commandInstance = binding.SourceExpression.ResolveAsSource(this.DataContext); object commandObject = commandInstance.Value; ICommand iCommand = commandObject as ICommand; //Get the property setter for the event to which we will bind TargetEvent evt = binding.ResolveAsTargetEvent(this.bindingContainer); //bind Type eventDelegateType = evt.Descriptor.EventHandlerType; Delegate handler = new EventHandler((s, e) => iCommand.Execute(this)); evt.Descriptor.GetAddMethod().Invoke(evt.OwningControl, new object[] { handler }); control.Visible = iCommand.CanExecute(this); //listen to canExecuteChanged iCommand.CanExecuteChanged += new EventHandler((s, e) => control.Visible = iCommand.CanExecute(this)); }
/// <summary> /// Execute a bind in the context of a collection container. /// </summary> /// <remarks> /// Specficy the target control directly. /// </remarks> /// <param name="control">The target control</param> /// <param name="collectionItemContainer"> /// The collection item container. E.g. In the case of a repeater a RepeaterItem. /// This is available from the ItemTemplate control via (IDataItemContainer)container.NamingContainer. /// </param> ///<param name="targetPropertyName">The property on the targetcontrol.</param> /// <param name="bindingOptions"></param> /// <returns>The result (value) of the bind</returns> public object ExecuteBind(IBindingTarget control, IBindingTarget <IDataItemContainer> collectionItemContainer, Options bindingOptions, string targetPropertyName) { if (control == null || bindingContainer == null || bindingOptions == null || string.IsNullOrEmpty(bindingOptions.Path)) { return(null); } object dataValue = null; BindingDef binding = null; IBindingTarget genericContainer = null; object baseContext = this.DataContext; if (bindingOptions.PathMode == PathMode.Relative && collectionItemContainer != null) { IDataItemContainer containerControl = collectionItemContainer.TargetInstance; dataValue = DataBinder.Eval(containerControl.DataItem, bindingOptions.Path); bool isCollectionBinding = DetermineIfCollection(control, dataValue); binding = new BindingDef(control, targetPropertyName, containerControl.DataItemIndex, DataStorage, bindingOptions, isCollectionBinding, controlService); genericContainer = collectionItemContainer; } else { dataValue = DataBinder.Eval(baseContext, bindingOptions.Path); bool isCollectionBinding = DetermineIfCollection(control, dataValue); binding = new BindingDef(control, targetPropertyName, bindingOptions, isCollectionBinding, controlService); genericContainer = controlService.GetParent(control); } //determine binding direction is not explicitly set based on the value and contorl if (bindingOptions.Mode == BindingMode.Unset) { bindingOptions.Mode = DetermineBindingDirection(control, dataValue); } //store the binding DataStorage.Add(binding); return(AttemptConvert(binding, dataValue, genericContainer)); }
private List <Control> SetupCollectionUnbindTest(Options options) { List <Control> createdControls = new List <Control>(); //Create a repeater from which we will read data Repeater rpt = new Repeater(); rpt.ItemTemplate = new DynamicItemTemplate(new List <Func <Control> > { () => new TextBox() { ID = "tb" } }); var item1 = new Child { Name = "Sam" }; var item2 = new Child { Name = "Ben" }; var item3 = new Child { Name = "Ali" }; var list = new List <Child> { item1, item2, item3 }; viewModel.ChildrensNames = list; //Create a binding collection collection = new Binding.BindingCollection(); //add in the parent binding, this will not be used in the bind but is required for unbind to work within a collection collection.Add(new Binding.BindingDef(new WebformControl(rpt), "DataSource", new Options { Path = "ChildrensNames" }, true, controlService)); //When the item is created, create a binding for it and add to the binding collection. //We will also had the itemtemplate create control to a collection so that we can stick some values //in to simulate user input before unbinding to the model. int index = 0; rpt.ItemDataBound += (s, e) => { TextBox tb = e.Item.FindControl("tb") as TextBox; WebformControl wrappedTb = new WebformControl(tb); options.Path = "Name"; Binding.BindingDef binding = new Binding.BindingDef(wrappedTb, "Text", index, collection, options, false, controlService); index++; collection.Add(binding); createdControls.Add(tb); }; rpt.DataSource = list; WebformControl dummyControl = new WebformControl(new TextBox()); //tell the mock conntrol service to return the collection result when required. this.controlService.Expect(cs => cs.FindControlUnique(null, null)).IgnoreArguments() .Do( new Func <IBindingTarget, string, IBindingTarget>((b, s) => { //we only need it return a non-null return(dummyControl); })); int counter = 0; //and setup service to return it controlService.Expect(cs => cs.Unwrap(null)).IgnoreArguments().Do(new Func <IBindingTarget, object>((t) => { Control ctrl = createdControls[counter]; counter++; return(ctrl); })); //setup viewmodel with default values viewModel.ChildrensNames = new List <Child> { new Child(), new Child(), new Child() }; //setup the data storage service to return the collection dataStorageService.Expect(ds => ds.RetrieveOrCreate <Binding.BindingCollection>(DATA_BINDING_KEY)).Return(collection); dataStorageService.Expect(ds => ds.RetrieveOrCreate <Binding.BindingCollection>(COMMAND_BINDING_KEY)).Return(new Binding.BindingCollection()); //and the viewmodel (we are using the view state binder which will try to resolve the service from storage dataStorageService.Expect(ds => ds.Retrieve <object>(null)).IgnoreArguments().Return(viewModel); rpt.DataBind(); return(createdControls); }
public void VerifyTextboxInRepeaterProgrammaticBindReturnsCorrectValue() { /*Arrange*/ List <Child> children = new List <Child> { new Child { Name = "Ben" }, new Child { Name = "Sam" }, new Child { Name = "Dave" }, new Child { Name = "Ali" } }; this.viewModel.Expect(vm => vm.ChildrensNames).Return(children).Repeat.Once(); //tell the mock conntrol service to return the collection result when required. this.controlService.Expect(cs => cs.FindControlUnique(null, null)).IgnoreArguments() .Do( new Func <IBindingTarget, string, IBindingTarget>((b, s) => { if (s.EndsWith("tb1")) { //we only need it return a non-null return(new WebformControl(new TextBox())); } return(null); })); //create a repeater and set its item template Repeater rpt = new Repeater(); rpt.ItemTemplate = new DynamicItemTemplate(new List <Func <Control> > { () => new TextBox() { ID = "tb1" } }); /*Act*/ Options options = new Options { Path = "ChildrensNames" }; object resolvedValue = this.binder.ExecuteBind(new WebformControl(rpt), options, "DataSource"); rpt.DataSource = resolvedValue; //When the repeater item is created bind up child controls and test the values returned from the binder rpt.ItemDataBound += (s, e) => { RepeaterItem rptItem = e.Item; TextBox rptItemControl = rptItem.FindControl("tb1") as TextBox; Options textBoxBindOptions = new Options { Path = "Name" }; object tbResolvedValue = this.binder.ExecuteBind(new WebformControl(rptItemControl), new WebformControl <IDataItemContainer>(rptItem), textBoxBindOptions, "Text"); Assert.AreEqual(children[rptItem.ItemIndex].Name, tbResolvedValue); }; rpt.DataBind(); /*Assert*/ //verify we have an repeater item for each item passed in on the datasource Assert.AreEqual(children.Count, rpt.Items.Count); //we should have one binding for each child control (4) plus the binding the on the parent(rpt) Assert.AreEqual((children.Count + 1), this.collection.Count); Binding.BindingDef parentBinding = collection[0]; Assert.IsTrue(parentBinding.IsSourceEnumerable); Assert.IsNotNull(parentBinding.Container); Assert.AreEqual(rpt, ((WebformControl)parentBinding.Container).Control); //test the child bindings for (int i = 1; i < collection.Count; i++) { Binding.BindingDef childBinding = collection[i]; Assert.IsTrue(childBinding.Parent == parentBinding); Assert.AreEqual(i - 1, childBinding.DataItemIndex); Assert.IsFalse(childBinding.IsSourceEnumerable); } }
private void ExecuteCommandBind(BindingDef binding) { TargetProperty target = binding.ResolveAsTarget(this.BindingContainer); ExecuteCommandBind(target.OwningControl, binding); }