WPF combobox ItemTemplate does not apply - c#

I have a combobox, which is bound to a dictionary of
<int, MyObject>
by the following code:
this.comboBox.ItemsSource= dictionary;
MyObject has some public properties, such as Name (string) and Selected (boolean).
In my Xaml I have an ItemTemplate on comboBox:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Key, Mode=OneWay}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
When I run the app, I get the combobox filled with [1, MyObject] values.
What I eventually want to do is have a checkbox and a textblock in the ItemTemplate, which will be bound to MyObject.Selected and MyObject.Name. At the moment, I can't even get the datatemplate to display the dictionaty Key value.
Any ideas why the itemtemplate is being ignored? I've tried the full temeplate (stack planel containing a combobox and textblock), that showed the same values at runtime.
cheers.

Related

WPF ComboBox bind text to selected item

I try to bind a ComboBox to a collection:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding YAxes}"
SelectedItem="{Binding SelectedYAxis, Mode=TwoWay}"
DisplayMemberPath="AxisTitle"
SelectedValuePath="AxisTitle"/>
Everything is fine, except Text of this ComboBox. On selection of item, the setter on SelectedYAxis fires and notifies, that property has been changed:
private IAxis _selectedYAxis;
public IAxis SelectedYAxis
{
get => _selectedYAxis;
set
{
_selectedYAxis = value;
OnPropertyChanged(nameof(SelectedYAxis));
}
}
but the text on ComboBox never changes to the selected items AxisTitle. How to display an AxisTitle of SelectedItem as a text of ComboBox?
UPD: Text is never shown, even if it's set explicitly:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding XAxes}"
SelectedItem="{Binding SelectedXAxis, Mode=TwoWay}"
DisplayMemberPath="AxisTitle"
Text="Asdasd"/>
It doesn't set the text of ComboBox to "Asdasd".
UPD 2: I've changed the things to use DataTemplate, but this didn't work as well:
<ComboBox Margin="4 0 2 0"
ItemsSource="{Binding YAxes}"
SelectedItem="{Binding SelectedYAxis, Mode=TwoWay}"
ItemTemplate="{StaticResource AxisCBTextTemplate}"/>
And the resource section above:
<DataTemplate x:Key="AxisCBTextTemplate">
<TextBlock Text="{Binding AxisTitle}"/>
</DataTemplate>
UPD 3
An illustration to what do I mean:
The task of displaying some selected text should be trivial, but it has difficulties.
I've found the root cause of this issue. Each IAxis (it is a SciChart axis object) from XAxes and YAxes is already dispayed on the graph (i.e. bound). Binding them to other controls (like ListBox) causes an exception: "Must disconnect specified child from current parent Visual before attaching to new parent Visual.", I found it out while trying to bind them to ListBox.
Seemes like ComboBox catches such exceptions and doesn't output StackTrace for any case. In my case this exception was wrapped into NullReferenceException and occurred only on click on a ComboBox, that has no ItemTemplate set. Though I may not be fully correct in details, replacing XAxes and YAxes with collections of strings solves this issue.

How to bind CheckBox IsChecked to ListBox of CheckBoxes

I have a list of check boxes and a single check box that acts as CheckAll/UncheckAll for all items in the listbox.
How can I make the chkAll Check Box checked if all the items are checked in the listbox binding ?
I could create a property in the view model to achieve that. I would like to do it in the xaml code.
<ListBox Name="listBox" ItemsSource="{Binding mySource}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelectedProperty}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Name="chkAll" Content="CheckAll/UnCheckAll" IsChecked ={}/>
I think you will need to have a higher-level view model property that reflects this additional state. The state has three possible values too, so be sure to set IsThreeState to true, and bind it to a Nullable<bool>.
Then in this property's setter, you can update all the other checkbox properties.
For each item's IsSelectedProperty, you'll need to update the three-state property too.

Read Text From TextBox in DataGrid MVVM (wpf databinding)

I have a datagrid of rows which contain data read from a web server and values I want to write into a webserver. I write the values in getting the user to input a number into the appropriate column and click an adjacent text box;
<DataGrid x:Name="datagridDERControl" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF322D2D" Height="382" Margin="10,78,10,10" Width="972" ItemsSource="{Binding Path=NFDataSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="100" Header="Write Set Point">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Width="100" Text="{Binding Path=WriteSetPoint, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="100" Header="Global Trip">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="buttonGlobalTrip" Width="100" Click="buttonGlobalTrip_Click"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid
How do I extract the specific textbox string per row to use in my view model.
It's always difficult to answer a question where the relevant details have been omitted by the question author. However, I shall try!
You have data bound (presumably) a collection property named NFDataSource to your DataGrid.ItemsSource property. That is the collection that represents the data in your DataGrid, so to 'extract' a specific value, you need to look into your data items in your collection.
One handy property in the DataGrid class is the SelectedItem property. this enables you to data bind an object (of the same type as those in your NFDataSource collection) to this property, which accesses the data object behind the row that is currently selected in the UI:
<DataGrid ItemsSource="{Binding NFDataSource}" SelectedItem="{Binding SelectedItem}" />
Now you can utilise your SelectedItem property to access the values from the selected row in the DataGrid:
string someValue = SelectedItem.SomeProperty;
As you tagged this with MVVM and databinding, I'll assume you're using these and have just got muddled.
"I have a datagrid of rows which contain data read from a web server
and values I want to write into a webserver."
So your viewmodel has a property, which is a collection of a custom class, that represents data fetched from a webservers.
"I write the values in getting the user to input a number into the
appropriate column and click an adjacent text box"
So this VM property is two-way bound to a datagrid, so that each item in the collection represents 'one row', and the properties on those items represent your 'columns'. The user can make changes to the UI displayed values, and because of the two way databinding the VM property is also updated.
"How do I extract the specific textbox string per row to use in my
view model."
Why do you need the specific textbox string, if it is databound to a property (or rather to a property on a class contained in a collection) in your VM anyway? If you've set up your VM this way, and are using databinding, you rarely need to worry about UI specific things such as which row in a datagrid is clicked.
As Sheridan points out though, you can also bind to properties on the datagrid such as SelectedItem so that you can perform additional operations beyond just reading/writing data. SelectedItem for your datagrid will be of the type that populates your VM collection, so will have the appropriate properties.
For example, if your VM collection is an IQueryable<Person> and that is bound to the ItemsSource of the datagrid then the SelectedItem will be of type Person. You could then have a VM property called SelectedPerson which is bound to that SelectedItem, and access things like SelectedPerson.Name etc.

selectedItem is not working in xaml

i am trying to set selected item through following code but its not working:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Sort by" Margin="10" VerticalAlignment="Center"/>
<ComboBox Width="{StaticResource ComboWidth}" x:Name="sortcombo" ItemsSource="{Binding Path=SortOrder}" SelectionChanged="SearchCombo_SelectionChanged" SelectedItem="{Binding Path=DefaultSortIndex}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Sort}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
however it works fine if i use selectedIndex instead with binding to 0th index. Any thing wrong with declaration?
By the name of your property DefaultSortIndex maybe you are trying to bind an int for SelectedItem.
SeletedItem refers to an element of your collection binded to ItemsSource, so the property binded to SelectedItem must be of type of your collection elements.
If you bind int value to selected item then it will not work, you should bind element for that. For int value you can set it as mentioned in following post :
Set Selected Item of WPF Combobox to User Setting
found out the issue, actually the data source was creating new list everytime I call getData().

Combobox not rendering in wpf datafrid

I have my data grid "dgSubsytem" column defined like below
<my:DataGridComboBoxColumn x:Name="cmbSubSysSupplier_SRV" Header="Supplier" Width="160"
ItemsSource="{Binding RelativeSource}" SelectedValueBinding="{Binding SupplierId}" />
As you see from the code i am having a combo box inside a grid .
Item source of this combo box is a datatable which is bound to it in the code behind .
Item source of the grid also another datatable bound in code behind .
code of binding item source of combobox in code behind is as follows
cmbSubSysSupplier_SRV.ItemsSource = dsComboBox.Tables[3].DefaultView;
cmbSubSysSupplier_SRV.DisplayMemberPath="FullName" ;
cmbSubSysSupplier_SRV.SelectedValuePath = "SupplierId";
Problem is combo box itself not rendering . But I can see the value of the Supplier rendered as text . What is the problem?
There are 2 parts here:
List of values to be populated in ComboBox: ItemsSource, should be bound using a StaticResource, with a List<X> fields exposed from your ViewModel.
The actual value (here X) should be bound to SelectedItemBinding using binding to data item.
No binding in code behind required.
At what point does your code-behind stuff run?
You're setting the ItemsSource in two places - in the XAML and in the Code-Behind. Whichever one runs second will overwrite the value of the first one, so only the last value set will be used.
I suspect your XAML is getting run last, and RelativeSource is probably not a property on your DataContext, so your ComboBox ends up being bound to nothing.
To fix it, simply remove your ItemsSource binding in the XAML for the DataGridComboBoxColumn
<my:DataGridComboBoxColumn x:Name="cmbSubSysSupplier_SRV"
Header="Supplier" Width="160"
SelectedValueBinding="{Binding SupplierId}" />
In addition, the DefaultView of a DataTable will return an object of type DataView, and DataView does not have properties called FullName or SupplierId, so your SelectedValuePath and DisplayMemberPath properties won't work.
I'd recommend building a list of KeyValuePair<int,string> out of your data items, and bind your ComboBoxColumn.ItemsSource to that list, then switch the SelectedValuePath to "Key" and the DisplayMemberPath to "Value"
I personally fought with DataGridComboBoxColumn for long time and i think the way is to use DataGridTemplateColumn. Here is an exemple :
Looks a lot of code but evective.
Put the collection as resource :
<Grid.Resources>
<CollectionViewSource x:Key="StructuresCollection" Source="{Binding StructuresList, Mode=OneTime}"/>
</Grid.Resources>
<DataGridTemplateColumn Header="Structure" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Structures.Name}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate>
<ComboBox x:Name="CStructures" SelectedItem="{Binding Structures}" DisplayMemberPath="Name" SelectedValue="{Binding IDStructure, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="{Binding IDStructure}" ItemsSource="{Binding Source={StaticResource StructuresCollection}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Categories