Can't use bindings in this context? - c#

So I have this code and I can't use the bindings!
<ListView.View>
<GridView>
<GridViewColumn Header="File name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<Image Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Left">
<Image.Source>
<MultiBinding Converter="{StaticResource fic}">
<Binding Path="FileName" />
</MultiBinding >
</Image.Source>
</Image>
<TextBlock Margin="16,0,0,0">
<Binding Path="FileName" />
</TextBlock>
</DockPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Long boring exception removed
<TextBlock Margin="16,0,0,0">
<TextBlock.Text>
<Binding Path="FileName" />
</TextBlock.Text>
</TextBlock>
... Seems to work!

Things inside <TextBlock> tags are items contained inside the text block, which can be a whole lot of spans and other text fragments.
If you need to bind the text in the text block, you need to bind to the Text property, as you've done in your question. It is a DependencyProperty that supports this binding.
The items inside the text block does not support direct binding, nor does it support directly putting binding objects in there. However, you may put in another control with a DependencyProperty that is a binding though.

You cannot bind the text of a textblock through its children.

Related

Click event on custom control in list view not always setting SelectedItem

I have a situation where I have a listview :
<ListView ItemsSource="{Binding Environments}" SelectedItem="{Binding SelectedEnvironment}">
<ListView.ItemTemplate>
<DataTemplate>
<controls:RadioButtonTextBox DataContext="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
which uses a custom control as its item template:
<StackPanel Orientation="Horizontal">
<RadioButton VerticalAlignment="Center">
<RadioButton.IsChecked>
<MultiBinding Converter="{converters:StringCompareToBooleanConverter}">
<Binding Path="." RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=UserControl}"/>
<Binding Path="SelectedItem" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListView}"/>
</MultiBinding>
</RadioButton.IsChecked>
</RadioButton>
<TextBlock Text="{Binding}" VerticalAlignment="Center" Margin="5,0,0,0" Style="{DynamicResource RedTextBlock}"/>
</StackPanel>
And the problem I have is that if the user clicks on the textblock of the custom control then the correct thing happens, i.e. the item is selected (and the view model updates accordingly), yet if the user click on the radio button of the custom control the radio button becomes checked but the selected item is not updated and the previously selected item does not get deselected.
Can anyone help with this issue?
The click is handled and not propagated by your radio button.
In cases where the item contains input elements i tend to bind IsSelected in the ItemContainerStyle to IsKeyboardFocusWithin. Not sure if this deselects the old item, maybe only if selection mode is Single.
The simplest solution I found was to simply set the enabled flag on the radio button to false:
<StackPanel Orientation="Horizontal">
<RadioButton VerticalAlignment="Center" IsEnabled="False">
<RadioButton.IsChecked>
<MultiBinding Converter="{converters:StringCompareToBooleanConverter}">
<Binding Path="." RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=UserControl}"/>
<Binding Path="SelectedItem" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListView}"/>
</MultiBinding>
</RadioButton.IsChecked>
</RadioButton>
<TextBlock Text="{Binding}" VerticalAlignment="Center" Margin="5,0,0,0" Style="{DynamicResource RedTextBlock}"/>
</StackPanel>

How do I bind a command to a Listbox Item?

I have a Listbox. I have the ItemSource of the Listbox bound to a list.
Within the ItemTemplate, I want to be able to add a MouseBinding to each item.
Here's what I have so far:
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="Blue" CornerRadius="8" >
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick" Command="{Binding Test}" CommandParameter="{Binding PropertyOfClickItem}" />
</Border.InputBindings>
<TextBlock Foreground="White" FontSize="24" FontWeight="Bold" Margin="5">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}
Seat: {2}">
<Binding Path="LastName" />
<Binding Path="FirstName" />
<Binding Path="Seat" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
I'm confused, because it seems that I can only bind to things within my ItemSource, but my "Test" command is not within that. How can I bind to a Command that's in the ViewModel for the View, instead of the ItemSource that's bound to the Listbox?
Not only that, but I want to be able to pass a property of the selected item to the command. Is this possible?
You can use the RelativeSource property of the binding to get an ancestor that has the DataContext you want. For example:
Command="{Binding DataContext.Test, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
Use a Relative Source like clcto said.
Look here for a complete answer:
WPF "static" binding in a List

DataGridTemplateColumn EditingElementStyle equivalent

I am coding the following piece of code and it is looking like it is functional. However once I get a validation error it stays even if the validation error has been corrected. I am using validation at row level as well as at cell level on my DataGridTextColumn using the EditingElementStyle parameter but this can't be used in a DataGridTemplateColumn. Is there an equivalent that I can use as I am not sure how to proceed. Below is a sample of my code showing one of my DataGridTextColumns and my DataGridTemplateColumn.
<dg:DataGridTemplateColumn Header="Instrument" MinWidth="140">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate >
<TextBlock Text="{Binding Path=PRODUCTNO, Mode=TwoWay}"/>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
<dg:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True" ItemsSource="{StaticResource TestList}">
<ComboBox.Text>
<Binding Path="PRODUCTNO" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationRules:IntegerValidationRule />
</Binding.ValidationRules>
</Binding>
</ComboBox.Text>
</ComboBox>
</DataTemplate>
</dg:DataGridTemplateColumn.CellEditingTemplate>
</dg:DataGridTemplateColumn>
<dg:DataGridTextColumn Header="BATCH No." Width="100" EditingElementStyle="{StaticResource CellEditStyle}">
<dg:DataGridTextColumn.Binding>
<Binding Mode="TwoWay" Path="BATCHNO">
<Binding.ValidationRules>
<ValidationRules:StringValidationRule/>
</Binding.ValidationRules>
</Binding>
</dg:DataGridTextColumn.Binding>
</dg:DataGridTextColumn>
Maybe try out what this person did. The code snippets on the page don't seem to work, but what he suggests is to rather use a customised DataGridTextColumn instead of DataGridTemplateColumn. I'm going to try that and I'll update my answer when (or if) it works.

Dynamically set Textblock size when Column containing it, is resized

I have an xceed grid (not sure if that is important) and one of the columns has a CellContentTemplate that has a TextBlock. Instead of the textblock width being automatically set to the size of the text, I want it to be the size of the column. I allow resizing, so this complicates things a bit. Is there a way to dynamically change the TextBlock width when the column gets resized, in code behind?
EDIT: CellContentTemplate
<DataTemplate x:Key="CellTemplate.TaskName">
<StackPanel Orientation="Horizontal">
<TextBlock Tag="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<TextBlock Text="{Binding Path=Name}" >
<ui:DragDropBinding.DragSource>
<Binding Mode="TwoWay" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type XceedProviders:DataGridControlWithSelectedItems}}" Path="BindableSelectedItems" PresentationTraceSources.TraceLevel="High"/>
</ui:DragDropBinding.DragSource>
</TextBlock>
</TextBlock>
</StackPanel>
</DataTemplate>
Hi this is because you enclosing TextBlock in StackPanel . One simple workaround is instead of two TextBlock use two Run to bind two properties like
<DataGridTemplateColumn Header="Name" Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Background="Green">
<Run Text="{Binding Name}"/>
<Run Text="{Binding Rollno}"/>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Now textblock will expand with the width of column .I hope this will help.

Hierarchical Data Structure WPF TreeListView DataTriggers

I am trying to make a tree list view that displays different information compared to the parent.
From what I have now, the Children display the same information as the parent. I was wondering, how I would do this. The last post I had didn't really quite make sense to me, it didn't work really well. I was wondering if anyone can explain this a little more in depth for me.
This is the last post:
Hierarchical Data Structure WPF TreeListView
<r:TreeListView x:Name="TimeSheetsTreeListView" Margin="0,-18.312,0,0"
Style="{DynamicResource TreelistStyle}" Width="Auto" MinHeight="150"
Grid.Row="0" Background="#00FFFFFF"
ItemsSource="{Binding TimeSheetItems, Mode=Default}"
HorizontalContentAlignment="Center"
VerticalAlignment="Top" Height="207.446" Foreground="White"
Grid:GridViewSort.AutoSort="True" >
<r:TreeListView.Columns>
<GridViewColumn DisplayMemberBinding="{Binding ClientMatterName}" Width="200"
Grid:GridViewSort.PropertyName="ClientMatterName" >
<GridViewColumnHeader HorizontalContentAlignment="Center" Foreground="White"
Content="Client Name/Matter Name"
Grid:GridViewSort.PropertyName="ClientMatterName"
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding ClientMatterCode}" Width="200"
Grid:GridViewSort.PropertyName="ClientMatterCode" >
<GridViewColumnHeader HorizontalContentAlignment="Center" Foreground="White"
Content="Client No./Matter No." FontSize="10.667"/>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding TimeCode.Code}" Width="100"
Grid:GridViewSort.PropertyName="TimeCodeCode" >
<GridViewColumnHeader HorizontalContentAlignment="Center" Foreground="White"
Content="Time Code" FontSize="10.667"/>
</GridViewColumn>
<GridViewColumn Header="Hours" Width="100" Grid:GridViewSort.PropertyName="Hours">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Left"
Text="{Binding Duration, Converter={StaticResource BillableHoursConverter}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="300" DisplayMemberBinding="{Binding Description}"
Grid:GridViewSort.PropertyName="Description">
<GridViewColumnHeader HorizontalContentAlignment="Center" Foreground="White"
Content="Description" FontSize="10.667"/>
</GridViewColumn>
</r:TreeListView.Columns>
<r:TreeListView.Resources>
<HierarchicalDataTemplate DataType="{x:Type data:TimeSheet}"
ItemsSource="{Binding Path= TimeRecords}"/>
</r:TreeListView.Resources>
</r:TreeListView>
if you want to display a parent-child relationship in a treeview. (only one level deep, so the children are all leaf nodes). you bind the treeview to the collection of parent elements. then you do a hierarchical data template for the parent, and a standard data template for the child
in the example you give you have a Parent of object type information with a collection of children object type detail and the collection of detail (children) on the parent is called child
so we do a template for the children, and then one for the parent
<!--Child (detail) DataTemplate-->
<DataTemplate
DataType="{x:Type local:detail}">
<TextBox Text="{Binding Path=Some child binding}"/>
</DataTemplate>
<!--Parent (information) Hierarchical Template-->
<HierarchicalDataTemplate
DataType="{x:Type local:information}"
ItemsSource="{Binding Path=Child}">
<TextBox Text="{Binding Path=Some parent binding}"/>
</HierarchicalDataTemplate>
because the parent and child are of a different object type, the tree view will grab the parent template, which has an items source and when it comes to draw the children it will use th child data template. note none of the data templates have keys, they are keyed on their object type.
your problem stems from the fact that both your parent and children are of the same type. the same template is used for both, what you need here is a data structure that is hierarchical.
if you had a parent task that had a collection of children and the children were of a different type than the parent then you would be cool. (because you could provide a different template for the children than the parent)
the other way to do it is to build a view model, with two different types, one for task overviews and one for sub tasks.
however i have found a hack solution using triggers based on collection sizes (when count is 0, i assume it is a leaf node) a better way would be to have a property on the object which states which type it is, parent or child, something you could easily do with a view model, or you could put the property on your business objects. go here and download the TreeViewTest.zip sample solution.
The above project is not an ideal solution. I create the view model every time. it gives you flexibility and control beyond what you have in straight wpf.
the project contains this code which is the tricky bit (note the string format on the bindings, they are really cool)
<HierarchicalDataTemplate
DataType="{x:Type local:Assignment}"
ItemsSource="{Binding Path=AssignmentCollection}">
<Grid>
<TextBlock
x:Name="parentTextBox">
<TextBlock.Text>
<MultiBinding
StringFormat="{}{0} - {1} - {2:F2}">
<Binding
Path="ClientName" />
<Binding
Path="Task" />
<Binding
Path="Hours" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock
x:Name="childTextBox" Visibility="Collapsed">
<TextBlock.Text>
<MultiBinding
StringFormat="{}{0:hh:mm tt} - {1:hh:mm tt} /{2}">
<Binding
Path="StartTime" />
<Binding
Path="EndTime" />
<Binding
Path="SubTask" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
<!--this is the trigger that chooses which text box to display-->
<HierarchicalDataTemplate.Triggers>
<DataTrigger
Binding="{Binding AssignmentCollection.Count}"
Value="0">
<Setter
TargetName="parentTextBox"
Property="Visibility"
Value="Collapsed" />
<Setter
TargetName="childTextBox"
Property="Visibility"
Value="Visible" />
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>

Categories

Resources