WPF: AutoCompleteBox SelectedItem - wpf

I have an object bound to controls in a window. There's a property on this object called "Region", and an ObjectDataProvider which is populated with a list of available "Regions". I'm using a WPF toolkit AutoCompleteBox to select the region selected but the value selected isn't update to reflect the region of the object. Eg: If I use the code below, I can open/save the form and the AutoCompleteBox appears blank, even though the region is saved (so it must be bound, but invisible?)
<input:AutoCompleteBox x:Name="txtRegionAuto" Grid.Row="0" Grid.Column="1"
IsTextCompletionEnabled="False" ValueMemberPath="Region" ItemTemplate="{StaticResource RegionDataTemplate}" Margin="2,4" Style="{StaticResource AutoCompleteComboBoxStyle}" TabIndex="8" SelectedItem="{Binding Region,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="lstRegion_SelectionChanged"
ItemsSource="{Binding Source={StaticResource regionProvider}}" MinimumPopulateDelay="400" />
The only way I can get the region to display in the box is with:
txtRegionAuto.SelectedItem = regions.FirstOrDefault(c => c.RegionID == region.RegionID);
But then when I come to save the form, the Region property on my object is null. I'm sure it's just a case of setting the right value binding, but I'm not sure what to use.

i guess you encountered a bug: https://connect.microsoft.com/VisualStudio/feedback/details/595640/autocompletebox-does-not-update-visible-text

Related

WPF - Using CollectionViewSource is Causing Erroneous Setter Call

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.

Set WPF CheckBox in a ComboBox to Checked

I have a custom WPF control - essentially a combo-box with check-boxes. The combo-boxes are successfully bound to a list of available items.
This control is to represent a field on a form. It is possible for the form to be completed already, in which case, the control must be rendered with the selected items - i.e. any items previously selected must be rendered as a checked CheckBox; it is here I'm running into trouble.
My first thought was to simply bind the IsChecked property - I don't think this can be done as the list of currently-selected-items is different from the list of available items which the ComboBox is bound to.
Basically, how do I gain access to the CheckBox object to set the Checked property to true? I've looked into this extensively and I can't fathom this out.
I'm using the ItemContainerGenerator approach - so when the user clicks on the drop-down, it is intended that a handler will iterate through the CheckBoxes and set the relevant boxes to checked.
Here's the XAML:
<ComboBox x:Name="FieldOptions"
ItemsSource="{Binding}"
HorizontalAlignment="Stretch"
Height="30"
KeyDown="FieldOptions_OnKeyDown">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="checkbox"
Content="{Binding Path=Text}"
Uid="{Binding Path=ID}"
FontStyle="Normal"
Foreground="Black"
Checked="CheckBox_OnChecked" />
</DataTemplate>
</ComboBox.ItemTemplate>
Any thoughts would be much appreciated.

How does wpf/databinding resolve this ambiguity?

<StackPanel DataContext="{StaticResource Employees1}">
<ListBox ItemsSource="{Binding}" DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True"/>
<Label Content="{Binding Path=Count}"/>
<Label Content="{Binding Path=Name}"/>
</StackPanel>
How does the binding for the labels get resolved? How is it decided that the content of the second label is bound to Employees1.Count (and not to Employee.Count), while the first label is bound to
Employee.Name and synchonized with the listbox selection? Also, what if I would like to bind the first label to Employee.Count instead?
(Employee has properties Name (and possibly Count), Employees1 is an ObservableCollection of type Employee).
EDIT: So, the question here is WHY the first label displays the number of employees in the ObservableCollection, while the second label displays the name of a specific employee in the collection, the one that is currently selected in the ListBox. Apparently, the first label binds to the entire collection, and the second label to a specific employee in the collection. But why, and how to control this behavior.
From MSDN Data Binding Overview, Binding To Collections, section "Current Item Pointer":
Because WPF binds to a collection only by using a view (either a view
you specify, or the collection's default view), all bindings to
collections have a current item pointer.
and section "Master-Detail Binding Scenario":
This works because when a singleton object (the ContentControl in this
case) is bound to a collection view, it automatically binds to the
CurrentItem of the view.
In your example, the second Label automatically binds to the current item of the default view of the Employees1 collection. The first Label would also bind like this, but since the item object does not have a Count property it apparently falls back to a binding to the Count property of the collection itself. However i don't know if the latter behaviour is documented somewhere.
As Blam says - the labels have no relationship to the listbox - I think what you're trying to do here is bind an observableCollection of Employees with properties Count and Name to the listbox..
To do this you'll need an ItemsTemplate in the listbox
<ListBox ItemSource={Binding Employees1}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Count}" />
<Label Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Let me try and answer the questions.
An ObservableCollection has a property Count.
As for getting a single property on the second label it is making some assumptions.
You might not get the same behavior in other version of .NET.
Should not bind a control that displays a single value to a collection.
If you want the selected item from the ListBox see this link
enter link description here

How to update an object's inner property from UI to VM? (WPF MVVM)

I have a property in my ViewModel, I'll call it "Project" which contains several nested lists inside of it. None of such lists has an associated property in the view model since I can show everything in xaml by using triggers and bindings.
My xaml shows the Project hierarchy in a treeview and its details in several views (a content control selects the right view depending on which item is selected on the treeview). One of those "details" is a property for the objects contained in one of the nested lists, I'm showing it in a textbox so the user can edit it, the problem I'm having is I don't see that property updated in the Project property in the VM once I make changes to it in the textbox.
I was told I have to create a property in the VM for that specific object's property I'm trying to edit, I just don't know how since the object is deep inside one of the nested lists of my Project object.
Common mistakes are:
Using OneWay binding mode instead of TwoWay
In XAML:
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
Not realizing that the update is not propagated to the VM until after the TextBox lost focus.
this is the default for the TextBox:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=LostFocus}" />
You could change it to:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />

Bind a ComboBox to two DataContexts

I have a ComboBox in my wpf application.
It's ItemsSource is binded to some table in my DataSet.
I need the text property to be binded to another's object property . I doesn't work because the ComboBox doesn't want to get two DataContexts. How can I solve this problem?
<StackPanel Width="Auto" Height="Auto" MinWidth="296" Orientation="Vertical" x:Name="MyStackPanel">
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding Path=MyProperty} />
</StackPanel>
In the code behind :
MyComboBox.DataContext = MyDataSet.Tables[MyTable];
MyStackPanel.DataContext = MyObject;
I want the ComboBox to show items from one DataContext but to show the text from another DataContext. How can I do it?
Don't use DataContext. Set the Source property of your bindings in XAML or create the bindings in code and set the Source property there.
Why are you assigning something to the datacontext of the stackpanel? From the looks of it, its not used.
Your code should work if MyDataSet.Tables[MyTable] returns an enumeration and contains a property called MyProperty.
What do you mean when you say that the combobox "doesn't want to get two DataContexts"?
Look into the properties IsEditable and IsReadOnly of the combobox.
Something like
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding ElementName=MyStackPanel Path=DataContext.MyProperty} />

Resources