Display a ListBox with a List of enums - wpf

I'm trying to display a ListBox inside of a GridViewColumn that needs to bind to a List of enums (List<ResourceType> Cost). The GridViewColumn's ListView is already bound to a collection of objects and I'm not really sure the best way to go about displaying the ListBox. Any suggestions?

You can bind the ListBox to a list of enum values. An easy way to do that is to use the markup extension I posted here.
Then, you need to bind the SelectedItem of the ListBox to the property displayed in the GridViewColumn.
You should end up with something like that :
<GridViewColumn Header="Resource type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListBox ItemsSource="{local:EnumValues local:ResourceType}"
SelectedItem="{Binding SelectedResourceType}">
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
EDIT: I think I misread your question... If I understand correctly, each object displayed in the ListView has a Cost property of type List<ResourceType>, right ? (btw, the fact that ResourceType is an enum doesn't matter here). So you just need to bind the ListBox to the Cost property :
<GridViewColumn Header="Resource type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Cost}">
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Related

How to bind to template-generated elements in a ListView

I have a ListView where for each item I'd like to add a TextBox for user input, and then be able bind to its content per selected item (or using an indexer) from outside of the ListView.
To illustrate:
<ListView Name="lv" ItemsSource="{Binding Source={StaticResource lvSrc1}}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Loc">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Name="tbGv" Text="User input" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<TextBlock Text="{Binding ElementName=lv, Path=SelectedItem[tbGv]}" />
Of course the above binding won't work, as SelectedItem returns an object from the underlying collection, which has nothing to do with the added TextBox.
How can I access the generated TextBoxes using pure XAML?
Edit:
I've now found a couple of posts with somewhat similar problems, where solutions presented are trickier than I expected and not based on XAML.
So rather, would it be possible to access ListViewItem (not the data its bound to) and its properties? This way I think I could pass text from my TextBox through the Tag property of ListViewItem.
I'm quite new to WPF so I assume that my problem and its phrasing is ridiculous, but please be gentle ;)

WPF: Deselect all my Checkbox when one is selected

This is my first ListView row column that contain CheckBox:
<GridViewColumn Width="40" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="cbSelectInterface" IsThreeState="False" ></CheckBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
How can i add the option to check only one CheckBox in specific Row and what i choose another CheckBox and check this control all other CheckBox become non selected ?
What about binding the CheckBox's IsChecked property to the ListViewItem's IsSelected property? If SelectionMode is set to Single, then you'll only be able to select one row and one checkbox.
<ListView ItemsSource="{Binding Source={StaticResource TestDataSource}}"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource
AncestorType={x:Type ListViewItem}}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding}" />
</GridView>
</ListView.View>
</ListView>
You can then use the ListView's SelectedItem to know which row is the one with the checked CheckBox.
In WPF, there is no control that automatically does what you want. However, implementing your requirement is simple, or at least, would be simple if you were using data binding as is customary in WPF applications. In that case, your view model or code behind would have an object (that would be data bound to the ListView.ItemsSource property) that contains all of the data items.
All you need to do when one of the Checkboxes is checked is to iterate through each item in the data bound collection and set their properties that are data bound to the Checkbox to false:
foreach (var item in YourDataBoundCollection)
{
item.PropertyDataBoundToCheckBox = false;
}
If you have implemented the INotifyPropertyChanged interface on your data class as you should have, then the UI will be automatically updated.
The only remaining question is how do you know when a CheckBox has been checked? The simplest 'non MVVM' way would be to add a handler for the CheckBox.Checked Event.

Data binding to a ViewModel property from a collections Binding?

I will try to keep this as succinct as possible.
I have a ViewModel with a collection of Models (i.e. Airplanes).
I have a Xaml page that is binded to the ViewModel.
The Xaml page has a DataGrid that is binded to the Airplanes collections.
For one of the DataGrid column templates, I want it to show a list of "EngineComponents", where EngineComponents is a collection of items defined in the ViewModel.
The catch is this:
The EngineComponents is a collection of parts that is essentially static. All Airplance rows in the DataGrid should show the same list of EngineComponents.
Airplanes
How to solve this EngineComponents binding question without writing extra code (event handlers, etc)?
You need to use a RelativeSource. I'll use a ListView in my example, but the ideas the same.
<UserControl ... DataContext="{Binding ...}">
<ListView ItemsSource="{Binding Airplanes}">
<ListView.View>
<GridView>
<GridViewColumn Header="Drawing No." Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.AvailableAirplanes,RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedItem="{Binding Airplane}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</UserControl>

WPF DataTemplate ComboBox binding issue

Edit: Rewritting question
I use the Project Management Library from http://dlhsoft.com/Home.aspx in my WPF usercontrol.
I'm displaying their LoadChartResourceListView control on my page and use a datatemplate to display custom columns in a list view:
<my:LoadChartResourceListView TaskManagerSource="{Binding ElementName=ganttChartTaskListView,Path=TaskManager}"
TimelinePageStart="{Binding TimelinePageStart, ElementName=ganttChartTaskListView, Mode=TwoWay}"
TimelinePageFinish="{Binding TimelinePageFinish, ElementName=ganttChartTaskListView, Mode=TwoWay}"
DisplayedTime="{Binding DisplayedTime, ElementName=ganttChartTaskListView, Mode=TwoWay}"
Margin="6" Name="loadChartResourceListView">
<my:LoadChartResourceListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource ListViewColumnHeaderContainerStyle}">
<!-- Set CellTemplate (or CellTemplateSelector) to specify column templates. -->
<GridViewColumn Header="Group" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="85" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type inf:MEFUserControl}}, Path=DataContext.ResourceGroups}"
DisplayMemberPath="GroupName"
SelectedValuePath="GroupID" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Resource">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="myTB" Text="{Binding Content}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The whole user control (inf:MEFUserControl) that contains this LoadChartResourceListView has a datacontext set to an instance of my viewmodel class (TaskData). Within the TaskData class is a ObservableCollection<ResourceGroup> ResourceGroups {get;set;}. Each ResourceGroup has an int GroupID {get;set;} and string GroupName{get;set;}.
Also, within the TaskData class is an ObservableCollection<Resource> Resources {get;set;} ... each Resource has a int GroupID{get;set;}, string Content {get;set;} and ResourceGroup ResGroup{get;set;}
The above code works fine with displaying the combobox and the textbox... I cannot, for the life of me, figure out why I'm having issues binding to the SelectedValue property of the combobox. I've many things including SelectedValue="{Binding GroupID}"
Everytime I try to set the SelectedValue I receive this error popup in VS:
"A first chance exception of type 'System.Reflection.AmbiguousMatchException' occurred in mscorlib.dll" This is the error from the output window (its massive) http://pastebin.com/AGJwn00C
From reading, I've read that this is due to a parent object having a property with the same name "GroupID". I've renamed GroupID to ResGroupID in the Resource class, thinking that it conflicted with the ResourceGroup class, but I receive the same error.
When I set this ItemsSource, is the DataContext for the combobox being set to the UserControl or TaskData instance?
Update:
I receive the error also when I use a TextBox instead of a combobox:
<TextBox Text="{Binding GroupID}"/>
Just write
SelectedValue="{Binding Path=GroupID}"
Solved it. After reading this: http://dlhsoft.com/KnowledgeBase/Task-Appearance-Bar-Templating-Custom-Data-Binding.htm
I had to do Item.PropertyName for custom properties.

Access control binding information from GridViewColumn

I have code like this
<GridViewColumn Header="Status" Width="75" DisplayMemberBinding="{Binding Path=TimesheetStatus}"/>
<GridViewColumn Header="Reviewed?" Width="70">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="1,2,1,0" IsEnabled="{Binding Path=EnableReview}" IsChecked="{Binding Path=IsReviewed}" Checked="reviewedCheckBox_Checked"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
I am able to access the displaymemberbinding property (TimeSheetStatus) for Gridviewcolumn Status.
But I want to know how can I access the IsChecked Binding property (IsReviewed) from the "Reviewed?" Gridviewcolumn.
Any help?
because you are using a data template, there is no nice way to get there, but if you only wants to get to this specific column binding you can try debug the application and look at the column in debug view till you get the to checkbox, write this path in your code and use the BindingOperations helper class to get the binding of the relevant property in your check box

Resources