TemplatedParent was not set to a child of UserControl - wpf

In my project, I have a Usercontrol which contains two child controls say a textbox and a button. A Common Style was written in App.xaml for Textbox. So this style will apply for that usercontrol's Textbox and in tat textbox when i tried to get the TemplatedParent it was null. How do i get the Usercontrol from the Textbox, so that the properties in the Usercontrol can be get in the textbox style.

TemplatedParent can be used within ControlTemplate.
For Style you need to use RelativeSource with mode set to FindAncestor and AncestorType set to UserControl.
Suppose you want to set Text to Name of UserControl from TextBox Style, you can do this way:
<Style TargetType="TextBox">
<Setter Property="Text"
Value="{Binding Path=Name,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl}}"/>
</Style>

Related

Set WPF Binding.StringFormat Property on TextBox via Style

I have an WPF application contains many TextBoxes having different kind of Bindings which all share the same StringFormat property (its a technical application, the Textboxes should display values with units "xxx mm"...)
I want to set up the Binding in the XAML/Designer, but I'd like to avoid setting the TextFormat property on every individual Binding. Is there a way to do this using Styles?
If I try to set the Binding in a Setter for the Text property like
<Style x:Name="mmtext" TargetType="TextBox" x:Key="mmtext">
<Setter Property="Text" Value="{Binding Path=A,StringFormat={}{0} mm}" />
</Style>
I need to provide a Path in the Setters Value property, and I cannot define any binding in the XAML itself (as this would override the value set in the Style).
Is there a way to set/modify only the StringFormat property in a single Binding (i.e. the Binding for the Text property) using a Style?
Or do I need to look for templating or a custom control?
you could probably bind the DataContext of the textbox rather than the text property
<TextBox DataContext="{Binding Path=A}" />
and then use a setter like
<Style x:Name="mmtext" TargetType="TextBox" x:Key="mmtext">
<Setter Property="Text" Value="{Binding Path=., StringFormat={}{0} mm}" />
</Style>
for a TwoWay binding you will need a converter anyways to get rid of the extra mms

How to change wpf listviewitem background color when its data is using binding?

I'm trying to change listview's row background color for a data binding listview.
From msdn, I know there is ListViewsItem.Backgroud for the color of its background.
But since I'm using data binding for ListView's data source,the type of ListView's item is actually my class type, no longer ListViewItem. So I can't find its Background property.
I guess I missed something, how should I do it?
Thanks
You can set ItemContainerStyle of your listview like below to set any property on item.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Red"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
You even change the background depending of dataitem state using triggers in style.

How bind to TemplatedParent from DataTemplate defined in a style?

I am developing a custom control derived from an ItemsControl. In the generic.xaml-file I created the style for that control and also defined an ItemTemplate:
<Style TargetType="local:MyItemsControl">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="Red">
<!-- Other things in here -->
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I want to bind the Background property of the Border in the DataTemplate to a dependency property of the MyItemsControl.
If found several questions here suggesting to use the element name of the MyItemsControl in the binding, but that only works when defining the ItemTemplate where the control is being used. I also tried binding to a RelativeSource defining the local:MyItemsControl as ancestor type.
Nothing worked. What am I missing here?
What`s the type of that DependencyProperty? Is it Brush or string?
This simple code works for me:
Background="{Binding Name, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Just for test here I bind to Name property of ItemsControl that is 'Yellow' - and it works.

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.

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