How can i bind a IsSelected Property to a textblock - wpf

my treeview is populated with textblock items.
If a user clicks on a textblock, i want to set a property in my model called "isSelected".
But : the textblock have no Property IsSelected.
How can i Implement this ?
Derive from textblock and add a Property ?

You have to use the TreeViewItem.IsSelected property. You will have to specify the custom style for all items of the tree view.
<TreeView>
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</TreeView.Resources>
</TreeView>

Related

Set parent controls property in xaml

I have a panel with a custom ListView. The ListView's items contains a GroupBox. The GroupBox contains a ListView. This ListView's items contains a GroupBox and so on.
All of the controls above have custom templates and styles
There are ToggleButtons in the Controls VisualTree lowest nodes.
When these buttons are checked I need to disable all the panel except of the button was clicked.
I would like to avoid event chaining through the parents in viewModel classes.
I'm using mvvm pattern and I would like to solve it in the xaml side if its possible.
EDIT: Here is a screenshot and the Pick button should disable the panel
Any suggestions are warmly welcomed.
you need to implement the relative source binding something like below.
IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=IsEnabled}"
Just have a read-only property in your ViewModel that is the negation of the property that your ToggleButton is bound to.
ViewModel:
private Boolean mSourceIsPicked;
public Boolean SourceIsPicked
{
get { return mSourceIsPicked; }
set
{
SetProperty("SourceIsPicked", ref mSourceIsPicked, value);
NotifyPropertyChanged("IsSourceChangeable");
}
}
public Boolean IsSourceChangeable
{
get { return ! this.SourceIsPicked; }
}
Then, in your View, just bind the IsEnabled property of the other controls to that new property.
<ComboBox ItemsSource="{Binding SourceTypes}"
IsEnabled={Binding IsSourceChangeable}" />
The advantage of binding to a property is that you can add/remove controls in your view and just bind to this property without changing additional XAML. You can also change the behavior of any control by not binding to this property.
If you really want a XAML-only solution, you can name each of the controls in the panel, and use a DataTrigger using TargetName on the "SourceIsPicked" property to disable the others:
<ComboBox x:Name="cboSourceTypes" ... />
<ComboBox x:Name="cboSourceNames" ... />
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding SourceIsPicked}" Value="True">
<Setter TargetName="cboSourceTypes"
Property="IsEnabled"
Value="False" />
<Setter TargetName="cboSourceNames"
Property="IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Note that this is all freehand, so you may need to adjust it a bit, but it gives you the idea.

Adding tool tip functionality to a wpf control that does not descend from FrameworkElement

I'm working on a custom class that descends from DataGridColumn. The base class for DataGridColumn is DependencyObject. As such, it does not have a Tooltip property.
I want my custom class to have a Tooltip property. Actually, I want it to also have a ToolTipTemplate property that is a DataTemplate that can be used to generate the ToolTip. How do I go about adding this functionality to my class?
Tony
Its a common misconception that DataGridColumn being a dependency object, is part of the visual tree. It is not. So even if we create an inheritable dependency property (just like DataContext or FlowDirection which automatically propagates down the visual parent to its child elements), the new property of ToolTip wont descend down to individual cells, as those cells are not the children of the data grid column.
So now that we know this, the only way left is to add a binding in the CellStyle and bind to the self Column.ToolTip property. Just because you have decided to go with ToolTipTemplate, then you could add a ContentControl and then bind to its content template.
Something like this...
<tk:DataGrid x:Name="MyDataGrid" RowHeaderWidth="15"
ItemsSource="{StaticResource MyData}"
AutoGenerateColumns="False">
<tk:DataGrid.CellStyle>
<Style TargetType="{x:Type tk:DataGridCell}">
<Setter Property="ToolTip">
<Setter.Value>
<ContentControl
ContentTemplate="{Binding Column.ToolTipTemplate,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type tk:DataGridCell}}}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding Column.ToolTipTemplate,
RelativeSource={RelativeSource Self}}"
Value="{x:Null}">
<Setter Property="ToolTip" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</tk:DataGrid.CellStyle>
....
</tk:DataGrid>

How to bind to the control's dependency property inside ControlTemplate

I've extended PopupBaseEdit control by adding my own ControlTemplate and a new DependencyProperty PopupText to the extended control. The property PopupText is initialized from the control's consumer. No issues here. The question is; how do I bind TextBox.Text to my attached property inside ControlContent?
Here is the XAML:
<ControlTemplate x:Key="myPopuptemplate">
<StackPanel>
<TextBox Margin="5" Text="???????"/>
</StackPanel>
</ControlTemplate>
<Style TargetType="local:myControl">
<Setter Property="PopupContentTemplate"
Value="{StaticResource myPopuptemplate}"/>
</Style>
Use a TemplateBinding.

ListView ItemContainerStyle Template

I created style to be used as my ListView's item template that contains a CheckBox and a TextBlock:
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListView}">
<Setter Property="SelectionMode" Value="Multiple"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="Template">
...
The checkbox in the template is bound to the IsSelected property of the list view item:
<CheckBox x:Name="itemCheckBox" Width="13" Height="13" Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
And the textblock's text is bound to the Value property of the source of the list view item:
<TextBlock x:Name="textBlock" Padding="5,0,0,0" HorizontalAlignment="Stretch">
<ContentPresenter Content="{Binding Path=Value}"/>
</TextBlock>
Each of the items in my list is an object that contains two properties, Value and IsChecked. What I am trying to do is bind the IsChecked property of my object to the IsSelected property of my list view item. However, I do not know how to access the IsChecked property of my object from within the ListViewItem template.
I didn't have any trouble binding the content of the text block to the Value property of my object but where would I even put the binding definition if I want the IsChecked property of my object to be bound to the IsSelected property of the list view item?
The DataContext for each ListViewItem should be set to the item data when it is created by the parent ListView so you should be able to use:
<Style TargetType="{x:Type ListViewItem}" >
<Setter Property="IsSelected" Value="{Binding IsChecked}">
...
</Style>

How can the ViewModel drive a ControlTemplate?

I have the problem that parts of the TreeView Controltemplate need to change depending on the state of the bound (ItemsSource) ViewModels. For example the little expander icon needs to be exchanged with a different drawing based on each items ViewModel state. Additonally based on the state of each ViewModel the child items need to be arranged horizontally instead of the default vertically.
It sounds like you have to customize ItemsContainerStyle, not ControlTemplate. For example, if you want to mark TreeViewItem as selected whenever underlying ViewModel is selected, you can use the following style:
<TreeView ItemsSource="{Binding ...}
...>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- IsSelected is a property on ViewModel item -->
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter .../>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
If Binding doesn't suit you, you can use Converters, Triggers in Style or ControlTemplate. Furthermore, you can also use triggers in DataTemplates.
PS: Wrote the code from head. May have a typo.

Resources