Bind a ComboBox to two DataContexts - wpf

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} />

Related

Binding ObservableCollection of strings to templated ListBox

I have this collection
ObservableCollection<string> Urls { get; set; }
inside my data context class. I have a binding to it in my list box:
<ListBox ItemsSource="{Binding Urls}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding .}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The data is diplayed in the list box, the two corresponding-not-shown-here buttons with commands Add and Delete work as well, however, the changing the TextBox does not affect the contents of the collection.
I have tried Mode=TwoWay in binding, but I figured that it is turned on already. I have tried some other options like Validate=OnPropertyChange, however, there is still nothing get updated.
How to make the TextBox inside that templated items in ListBox actually update the Urls property of a datacontext class?
You cannot modify strings; use a wrapper class with one string property, then bind the TextBox to said property. That way the strings in the property can be replaced with the edited ones.

Bind datagrid to one ViewModel, column / combobox to another

I a have a View Players, the datacontext is set to a ObservableCollection Players from the ViewModel MainPlayerViewModel.
In the View I have a datagrid with columns TeamId, Name and Position.
I want to bind the TeamId column with a combobox to a list of available teams from the MainTeamViewModel which has a collection property Teams but of course I want the MainPlayerViewModel to be updated whenever I update the team for a player.
I hope you can follow me here..
This is my xaml:
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}"
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Teams,
Mode=TwoWay}" SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
When I edit the cell it shows the list of available teams but the selectedvalue I pick from the list doesn't turn up in the TeamId column
How do I pull this off?
Kind regards,
Mike
UPDATE:
Despite the help I received I didn't get it to work binding one View to 2 different Viewmodels.
Guess the solution offered is long above my head..
I couldn't set the datacontext of the datagrid to MainTeam because it has an ItemsSource of players and a selecteditem bound twoway to selectedplayer.
Anyway I decided to keep it 1 View / 1 ViewModel and created a public property on my PlayerViewModel named teamsVM:
public MainTeamViewModel teamsVM
{
get
{
return ViewModelLocator.Container.Resolve<MainTeamViewModel>();
}
}
Now I can set the Itemsource to this new property and my player row get's updated when I change teams:
<DataTemplate>
<ComboBox
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding teamsVM.Teams,
Mode=TwoWay}" SelectedValue="{Binding Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid" SelectedValuePath="Model.teamid"/>
</DataTemplate>
Regards,
Mike
I find two things wrong with this code.
You are missing the SelectedValuePath for the ComboBox. Even though you bind all teams to it, the selected item's id is null because the SelectedValuePath is missing.
You also have a DataContext and an ItemsSource. Use only the ItemsSource for the teams you want to display, and the SelectedValue to be bound to the player's teamId, unless your view model has a "Teams" property and a "Player" property, in which case the DataContext may be used. (Id set the DataContext in code though...)
So yo will end up with something like this:
ItemsSource="{Binding Teams, Mode=TwoWay}" //Bind to all teams.
SelectedValue="{Binding Player, Path=TeamId, Mode=TwoWay}" //Bind to the teamId of the player.
DisplayMemberPath="TeamName" //that's the Name of each team.
SelectedValuePath="TeamId" //that's the Id of the team.
Two problems here:
First, as #bleepzer noted you did not specify the value/display paths in your combo box.
Second, you trying to access a property in the data context that is outside your grid (i.e. the main view model's data context) from within a data template. In silverlight 4 there is no relative source binding (something you would use in SL 5 or WPF), so you will have to use element binding to archive what you want.
Here is an example based on your code. It is not complete as it leaves out some of the DataGrid elements needed, but it shows the concept:
<data:DataGrid x:Name="myDataGrid"
DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}" >
<!-- additional stuff needed here -->
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding ElementName=myDataGrid, Path=DataContext.Teams}"
SelectedValuePath="TeamId"
DisplayMemberPath="TeamName"
SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
<!-- additional stuff needed here -->
<data:DataGrid>
And here is the description:
Add a name to your data grid.
Make sure the data grid has the right data context, either by setting it explicitly as in the sample, or inheriting it from the parent hierarchy.
Modify your ComboBox's ItemsSource property to point to the data grid using the element name you specified earlier. As you are now on the element and not on the data context you have to use DataContex.Teams to access the Teams property on the data context of your grid. The ItemsSource does not need two-way-binding as the view does not write anything back to your view model.
Specify the SelectedValuePath and DisplayMemberPath properties.
Finally, bind the SelectedValue property of the combo box to your rows model TeamId property using two-way-binding - needed now as the view should update the model's value. Important: the SelectedValue property of the combo box has to be bound after the ItemsSource to prevent some problems with the combo box.

Bind RibbonComboBox.SelectionBoxItem

I'm trying to bind the item selected in a RibbonComboBox to a property of an object. The problem I'm encountering is that the RibbonComboBox.SelectionBoxItem only provides a get accessor; therefore, I cannot bind it to anything in the XAML.
Any ideas how to bind the item to the property of an object? I could use a regular ComboBox is there another more appropriate control?
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
<ribbon:RibbonComboBox
ItemsSource="{Binding Source={StaticResource CollectionOfPossibleChoices}}"/
SelectionBoxItem="{Binding Path=PropertyToBindTo}"/> <!--Not valid-->
RibbonComboBox is unlike ComboBox (which i, also, find confusing). Try this;
<ribbon:RibbonComboBox>
<ribbon:RibbonGallery SelectedItem="{Binding Path=PropertyToBindTo}">
<ribbon:RibbonGalleryCategory ItemsSource="{Binding Source={StaticResource CollectionOfPossibleChoices}}" />
</ribbon:RibbonGallery>
</ribbon:RibbonComboBox>
MSDN Reference

MVVM ListBox controlling a Content Control

I've been going round in circles with this for a couple of days, and I'm hoping a WPF guru can see where I'm going wrong.
I'm setting CurrentViewModel in code. The Selected item of my ListBox and the Content of my ContentControl bind correctly. But when changing the selected item in the Listbox via the UI the CurrentViewModel is being set but the Content Control is not being updated.
I'm using a data template to map my Views and View Models.
<DataTemplate DataType="{x:Type ViewModel:MyViewModel}">
<View:MyView />
</DataTemplate>
I have a ListBox which is bound to an observable collection of ViewModels. The Selected Item is bound to the current view model.
<ListBox ItemsSource="{Binding MyViewModelCollection}" DisplayMemberPath="DisplayName" SelectedItem="{Binding CurrentViewModel, Mode=TwoWay}"/>
I also have a content control that is also bound to the CurrentView Model
<ContentControl Content="{Binding CurrentViewModel, Mode=TwoWay}"/>
This is the property that they are both bound to
public MyViewModel CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel== value) return;
_currentViewModel= value;
OnPropertyChanged("CurrentViewModel");
}
}
I've edited the names for clarity and removed formatting information.
Any help greatly appreciated.
Cheers,
Daniel
EDIT: Came across the link How can I debug WPF bindings?. I set a break point on the Content binding and it does indeed only get called once when the binding is first set.
You should not be setting TwoWay as the mode on your ContentControl:
<ContentControl Content="{Binding CurrentViewModel, Mode=OneWay}"/>
This is because you intend your ContentControl to read the value, but never write it.
As an aside, you can also bind the ContentControl to the currently selected item in the collection, rather than to that property by doing this:
<ListBox ItemsSource="{Binding MyViewModelCollection}"
DisplayMemberPath="DisplayName"
IsSynchronizedWithCurrentItem="True"/>
<ContentControl Content="{Binding MyViewModelCollection/}"/>
The "slash" (/) at the end of the collection indicates the current item selected in the collection and setting that current item property is as simple as setting the IsSynchronizedWithCurrentItem equal to true.
A lot of times I find with this combination, I really don't need the extra property on my view model.
Anyway, I hope this helps.

Silverlight 3: Using list of UserControls as ItemsSource for TreeView

I want to populate a TreeView with UserControls, but I only want the Name property to show up, not the entire UserControl. The following code gives me weird crashes as soon as I add something to myUCs:
C#:
var myUCs = new ObservableCollection<UserControl>();
MyTreeView.ItemsSource = myUCs;
XAML:
<controls:TreeView x:Name="MyTreeView">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
Does anyone know how to use a list of UserControls as an ItemSource for TreeViews?
I found one not so convenient workaround: instead of a List of UserControls, use a Dictionary, and change the XAML to:
<controls:TreeView x:Name="MyTreeView">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key.Name}"/>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
The same bug(?) exists in ListBox, a solution is provided here:
Use UIElements as ItemsSource of ListBox in Silverlight
That particular fix does not work for TreeView
You may have to create your own class that extends UserControl and override the ToString() method so that it returns the name property.

Resources