Access control binding information from GridViewColumn - wpf

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

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 ;)

Binding GrivdViewColumn's Width Property in XAML or in Code?

I would like to bind GrivdViewColumn's Width Property with my ViewModel. Lets say an instance of ViewModel is the Datacontext of the Window. ViewModel has got Properties called IdWidth, LastNameWidth, FirstNameWidth. And that Window contains the following given ListVeiw in a stackPanel. Everything is fine but somehow the Width Property of GridViewColumn is not bound. Please post the code after making sure that it works.
<ListView Name="PatientListView"
ItemsSource="{Binding Patients}"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Patient-Id"
Width="{Binding IdWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding PatientId}"/>
<GridViewColumn Header="Last Name"
Width="{Binding LastNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding LastName}"/>
<GridViewColumn Header="Last Name"
Width="{Binding FirstNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding FirstName}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
The accepted answer is wrong as outlined in my comment, looking at your paths you seem to expect the DataContext to be the item, which cannot work (there are multiple items to begin with, which should be chosen?).
The DataContext of the columns is the DataContext of the ListView.
This example will result in a column with the Header Lorem Ipsum:
<ListView>
<ListView.DataContext>
<Label Content="Lorem Ipsum"/>
</ListView.DataContext>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding Content}"/>
</GridView>
</ListView.View>
</ListView>
Also you might be interested in this article on debugging databindings.
Edit: FrameworkElement is not required for DataBinding, sorry for this incorrect interpretation of the citation from MSDN below.
See comments and #H.B. 's answer
GridViewColumn does not inherit from FrameworkElement, which is required for databinding.
see MSDN:
Support for data binding and dynamic resource references: [...], but the ability to resolve a member value that is stored as an Expression (the programming construct that underlies both data binding and dynamic resources) is implemented by FrameworkElement

Get GridViewColumn from control inside DataTemplate

Example:
<ListView Name="lvAnyList" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="xx" DisplayMemberBinding="{Binding XX}" CellTemplate="{DynamicResource MyDataTemplate}"/>
<GridViewColumn Header="yy">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding YY}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
If I access the TextBlock inside DataTemplate I will have access to information about the bound path.
But I don't know how to find (starting from the TextBlock) its containing GridViewColumn (which is in the GridViewRowPresenter columns list) and compare it to the grid's GridViewColumn (from GridViewHeaderRowPresenter column list) to get the header's name.
At the end I should have the pairs: xx->XX, yy->YY
I can find a list of all TextBlocks inside ListView by using this:
GridViewRowPresenter gvrp = ControlAux.GetVisualDescendants<GridViewRowPresenter>(element).FirstOrDefault();
IEnumerable<TextBlock> entb = GetVisualDescendants<TextBlock>(gvrp);
I can find a list of all GridViewColumnHeaders:
GridViewHeaderRowPresenter gvhrp = ControlAux.GetVisualDescendants<GridViewHeaderRowPresenter>(element).FirstOrDefault();
And I cannot find the connection between the TextBlocks and the GridViewColumns...
I hope this is understandable.
GridViewColumns are abstract objects they never appear anywhere in the UI, you can try to name the column and bind it to the Tag of a control where you need it using ElementName or if that fails a Source with x:Reference on the name.

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.

Multicolumn listview in WPF at design time

I might sound dumb here, but I want to do something really simple. At design time, I want to add columns to a listview control and add some data to it. I need to add combobox in each column of the listview. The thing I am not able to find is where to mention the column number in the listviewitem. Any help appreciated guys.
<ListView IsSynchronizedWithCurrentItem="True" Margin="8,68,304,188"
BorderThickness="2,2,2,2">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Column1"/>
<GridViewColumn Width="150" Header="Column2"/>
</GridView>
</ListView.View>
<ListViewItem>
</ListViewItem>
</ListView>
Each column in the listviewitem is rendered based on the GridView definition, so there is no real concept of column numbers. What you do is bind objects to the the listview's itemsource and it creates listviewitems from it. Thus, there are a few hoops to jump through.
This link has an example of how to do some simple object data binding. The advantage of this is what binding structure you have for design time can probably be reused for run-time if you set the datacontext/itemsource to an empty object instead of the static one in XAML.
If you're doing this to show examples or you just have a static data source that you want to use, I would recommend using the XmlDataProvider. Then you'd change your ListView to be like this,
<ListView IsSynchronizedWithCurrentItem="True" Margin="8,68,304,188"
BorderThickness="2,2,2,2">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Column1" DisplayMemberPath="{Binding XPath=/A/B}"/>
<GridViewColumn Width="150" Header="Column2" DisplayMemberPath="{Binding XPath=/A/C"/>
</GridView>
</ListView.View>
<ListViewItem>
</ListViewItem>
</ListView>

Resources