I am using a Combobox, in the controller the binding is done below and for some reason I need to delete few items from the Combobox So in onAfterRendering method I am removing the items as below.
this.byId("idaddrusages").removeItem(3);
The items were removed, however If I access the view in the same session it is throwing an error
Uncaught (in promise) Error: Error: adding element with duplicate id
'__xmlview0--container-component---newAddress--idNewAddUsagesItm-__xmlview0--container-component---newAddress--idAddressUsages-3'
If I refresh the page with a new session the items were removed from the Combobox.
View
<ComboBox id="idaddrusages" >
<core:Item id="idNewAddUsagesItm" key="" text=""/>
</ComboBox>
This is wrong way to declare combobox
<ComboBox id="idaddrusages" >
<core:Item id="idNewAddUsagesItm" key="" text=""/> // don't give id to item hence it complaints about duplicate id's
</ComboBox>
Secondly, better way to do is use local json model using your own defined json data or from odata model and bind the ComboBox as shown below
<ComboBox id="idaddrusages"
items="{
path: '/CollectionName'
}">
<core:Item key="{key}" text="{text}" />
</ComboBox>
Then you can remove items by just updating your model the way you like and combobox should be updated automatically
Let me know if it works for you.
DOM Manipulation is not working here n this case, hence we have removed the items from the model it self.
Related
I have a ComboBox that shows empty space below its values. See picture below.
The data in the view model is set in a button click handler. When I set the values in the initialization of the view model the ComboBox is fine. When I try to create a small example the ComboBox also has the expected size. It seems it depends somehow on the context where I set the values in the view model but I cannot figure out. I hope someone can give me a hint.
Code in the view model
Repositories.Clear();
Repositories.Add("One");
Repositories.Add("Two");
Repositories.Add("Three");
SelectedRepository = "One";
Code in XMAL
<ComboBox MinWidth="150"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
IsEnabled="{Binding CT.Connected}"
ItemsSource="{Binding CT.Repositories,
UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding CT.SelectedRepository}"/>
The ItemsSource you are binding to needs to be an ObservableCollection. The ComboBox will display the initial blank space if you bind the ItemsSource to any enumerable type that doesn't raise property changed when its items change.
When I try to create a small example the ComboBox has the expected size.
By that logic it maybe not the combobox, but the data which is in the list. Can you verify that there are not 8 items where the textual value to display is empty for the last four items or so?
Or
Maybe a style is causing the extra space. Try removing the style from the combobox such as this
<ComboBox Style="{x:Null}"/>
and see if it has any effect to the visual result.
Or
Also how about not setting the data and see if the drop down has the same size?
WPF, MVVM
I'm finding that if I use a CollectionViewSource with my ComboBox, when I close the window, an extra call to the SelectedValue Setter is executing, if SelectedValue is bound to a string property. If I set the ItemsSource binding directly to the VM, this call does not happen. The extra call is causing values to change in the VM, resulting in incorrect data. I have other ComboBoxes setup the same way, but they bind to integer values.
CollectionViewSource definition:
<CollectionViewSource x:Key="AllClientsSource" Source="{Binding AllClients}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="ClientName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
ComboBox with CollectionViewSource:
<ComboBox Grid.Column="2"
ItemsSource="{Binding Source={StaticResource AllClientsSource}}"
DisplayMemberPath="ClientName" SelectedValuePath="ClientId"
SelectedValue="{Binding Path=ClientId}"
Visibility="{Binding Path=IsEditingPlan, Converter={StaticResource BoolVisibility}}" />
ComboBox direct to VM (Forgoing sorting):
<ComboBox Grid.Column="2" ItemsSource="{Binding AllClients}"
DisplayMemberPath="ClientName" SelectedValuePath="ClientId"
SelectedValue="{Binding Path=ClientId}"
Visibility="{Binding Path=IsEditingPlan, Converter={StaticResource BoolVisibility}}" />
Can anyone tell me why there is an extra setter call using the CollectionViewSource? What's different about the string binding? Is there a way to properly work around it?
EDIT: I tried changing it up and using the SelectItem property on the ComboBox. Same result. So it seems that if the item is a scalar data type, it works as expected. If it's an object, you get an extra setter call with a null value. Again, if I remove the CollectionViewSource from the equation, it works as expected.
EDIT, AGAIN: I added a link to a sample project that illustrates the issue. Targets .Net 4.5.
Run the project.
Click to display View One
Select a Client and the client's name will display on the right.
Click to display View Two
Go back to View One - Note that the selected client is no longer selected.
Click to display View Three
Select a Region and the region's name is displayed on the right.
Go back to View Two
Go back to View Three - Note that the selected region is still selected.
The only difference between the views is that One and Two use a CollectionViewSource. Three binds directly to the ViewModel. When you move to a new tab from One or Two, the setter for the selected item is getting called with a null value. Why? What's the best work-around?
Thanks.
Apparently this is caused when the CollectionViewSource is removed from the visual tree... I moved the CollectionViewSource to the ViewModel and exposed it as a property and the issue is effectively worked-around.
I have a ListView with 3 columns (User Name, Active, and Group) The ItemsSource is bound to a staticresource
ItemsSource="{Binding Source={StaticResource SortedUsers}, UpdateSourceTrigger=PropertyChanged}"
the static resource is defined as:
<CollectionViewSource x:Key="SortedUsers" Source="{Binding UsersList, UpdateSourceTrigger=PropertyChanged}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription
Direction="Ascending"
PropertyName="UserName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
The user can select an item in the list and click "Modify" to change information about the user or can click an "Add" button to add a new user to the list. Both the Add and Modify use the same modal dialog to allow setup/modify of a new user. Adding a user works fine, the new user shows in the list once the modal dialog closes. however, modifying an existing user doesn't update the data in the ListView until the window that contains the listview is closed then reopened. What do i need to do to have the ListView update for modify?
Did u try using
((CollectionViewSource)this.FindResource("SortedUsers")).View.Refresh();
Although in MVVM the steps above wont be allowed.
So if the source collection (UsersList) is ObservableCollection collection view source will atomatically refresh on collection changed notifications of UsersList.
Let me know if this helps.
Do your data objects implement INotifyPropertyChanged interface?
See: https://stackoverflow.com/questions/6713288/databinding-fail-after-using-controltemplate/6713334#6713334
INotifyPropertyChanged notifies the UI that something has changed on the class implementing it. Of note: I dont know what kind of collection you are using to hold your classes (which gets passed into the CollectionViewSource), but I almost always use ObservableCollections. They implement CollectionChanged and notify the UI when items are added, removed and the collection is refreshed.
I'm trying to set seletected value to a pre-loaded combobox using silverlight with MVVM.
I load these combobox items before selecting value.
For example I have a combobox to select a country. My first step is to load a List which is bound to the combobox source. This is loading perfectly.
After this, I have a "SelectedCountry" object bound to the selectedItem of the combobox in a two-way binding.
This is working perfect when I select any of the combobox values and my SelectedCountry object is correctly selected.
The problem comes when I try to assign the selected value in my ViewModel. This way, the combobox selecteditem is not updated.
I suppose this is because, on fact, they are not the same object (they have the same values but they are diferent references).
Should this work if I re-implement the equals method? Or should I find the same object by searching into the List?? This would be very easy because this two countries would be the same if they have the same id... but I can have more complex objects and I think the equals method would be better.
Thanks in advance!!
Edit for adding some code example:
<ComboBox Grid.Column="7" Margin="6,0" Name="cBTipoPoliza" VerticalAlignment="Center" TabIndex="4" ItemsSource="{Binding TiposPolizas, Mode=OneWay}" SelectedItem="{Binding TipoPoliza, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding nombre_tipo}" />
</DataTemplate>
</ComboBox.ItemTemplate>
Usually I just override the .Equals() method to check if they are equal by ID or Name
You should try to avoid having multiple copies of the same object in memory at the same time. One method to do this is to have your VM be the source of objects. When you load the list have the VM do it and expose an AvailableCountries ObservableCollection property on the VM that your ComboBox can bind to.
If your objects are semantically equal based on ID, definitely override Equals and == and != and hashcode. However be careful because if you're enabling people to update the objects you can run into collisions (even within the same instance of the app) where one screen is holding onto stale data.
I have question on the checkbox.
First of all,
I have a usercontrol which has a list box like this and this user control will be switched by 2 button and then the data source is changed and then the the displayed officer status will be changed:
When I check the checkbox, Officers[0].IsOnDuty will be changed to true.
The problem is:
When I click another button and switch to another data source, this checked check box is still checked but the Officers[0].IsOnDuty for this data source is false.
How to solve this?
The data context of the list box item is an item for your officers collection, not the collection itself. And using a one way binding is incorrect, as the data source (the officer) will not be updated. So change the DataTemplate to:
<CheckBox IsChecked="{Binding Path=IsOnDuty, Mode=TwoWay}" />
*Here is the list box xaml:
<ListBox ItemsSource="{Binding OfficersCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Officers[0].IsOnDuty, Mode=OneWay}" />
*
The problem with your approach is that once you change the ItemsSource (by switching to the next page) your chekcbox is still bound to the item of the first collection. I think this happens because you explicitly use an indexer for the binding Path=Officers[0].IsOnDuty
Your samplelist box xaml does not really make sense. the ItemsSoruce is a OfficerCollection and your ItemTemplate binds to a collection of Officers too. Depending on what you are trying to accomplish you should do one of the following:
If your are just interested in the first officer (as your sample suggest), add a DependencyProperty FirstOfficer (or a INotifyPropertyChanged) property to your collection and bind to it: IsChecked="{Binding Path=Officers.FirstOfficer, Mode=OneWay}"
If you however are interested in all Officers and want checkboxes for all of them you should create a DataTemplate for the Officer type and use this as the ItemTemplate.
Generally you can stay out of a lot of trouble if you stick with MVVM and really tailor your ViewModel objects very close to what the View needs so you can bind your View to the ViewModel in the simplest possible way. Think of the ViewModel as the View you want to build but without a visual representation.