In my xaml I have a ItemsControl. Is is possible to have the ItemIndex property on ItemsControl? Basically I want to hide one of the child controls (TxtNodeData) if the Item index is 1
<ItemsControl ItemsSource="{Binding ConditionList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding NodeData}" Name="TxtNodeData"/>
<Button Content="+" />
<ComboBox ItemsSource="{Binding NodeNames}" DisplayMemberPath="name" SelectedValue="{Binding ConditionalNodeId, Mode=TwoWay}" SelectedValuePath="id"> </ComboBox>
<Button Content="-" />
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
You could do it with combination of AlternationCount set to number of items in the list and trigger on AlternationIndex being 1
<ItemsControl ItemsSource="{Binding ConditionList}" AlternationCount="{Binding ConditionList.Count}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding NodeData}" Name="TxtNodeData">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger
Binding="{Binding
RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}},
Path=(ItemsControl.AlternationIndex)}"
Value="1">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<!-- other controls -->
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Related
I have a DataGrid that consists of some columns. In one DataGridTemplateColumn, I want to use a condition. If the condition is False, it should display a single bound property. If the condition is True, it should display multiple bound properties (that's what I can't accomplish). How can I use WrapPanel under DataTrigger Setter?
My XAML code:
<DataGrid x:Name="DG_SipList" ItemsSource="{Binding Items3}" Margin="0 8 0 0" CanUserSortColumns="False" CanUserAddRows="False" AutoGenerateColumns="False" VerticalAlignment="Top" HorizontalAlignment="Left" materialDesign:DataGridAssist.CellPadding="13 8 8 8" materialDesign:DataGridAssist.ColumnHeaderPadding="8" IsReadOnly="True" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" >
<DataGrid.Resources>
<Style TargetType="TextBlock" x:Key="cfgText">
<Style.Triggers>
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="False">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="TextDecorations" Value="Underline"/>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBlock" x:Key="cfgText2">
<Style.Triggers>
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="START" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="cb_MontajStart" Checked="cb_MontajStart_Checked" Unchecked="cb_MontajStart_Unchecked" IsChecked="{Binding LISTE_MONTAJ_START}" HorizontalAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="ID">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=LISTE_KIMLIK}" Tag="{Binding Path=LISTE_MONTAJ_START}" Style="{StaticResource cfgText2}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="PRODUCT" MaxWidth="450">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding konfTanim}" Value="False">
<Setter Property="Text" Value="{Binding LISTE_URUN}"/>
</DataTrigger>
<DataTrigger Binding="{Binding konfTanim}" Value="True">
<Setter>
<!--This is what I can not combine more than one textblock under Datatrigger Setter-->
<WrapPanel Orientation="Horizontal" MaxWidth="450">
<TextBlock Text="{Binding Path=yeni_ModelTanim}"/>
<TextBlock Text="{Binding Path=MT4}" Tag="{Binding Path=monStd4}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT5}" Tag="{Binding Path=monStd5}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT6}" Tag="{Binding Path=monStd6}" Style="{StaticResource cfgText}"/>
</WrapPanel>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- ........................................................... -->
<DataGridTemplateColumn x:Name="txt_Configuration" Header="configuration" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<WrapPanel Orientation="Horizontal" MaxWidth="450">
<TextBlock Text="{Binding Path=yeni_ModelTanim}"/>
<TextBlock Text="{Binding Path=MT4}" Tag="{Binding Path=monStd4}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT5}" Tag="{Binding Path=monStd5}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT6}" Tag="{Binding Path=monStd6}" Style="{StaticResource cfgText}"/>
</WrapPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
In case of multiple different representations of the same type, depending on a flag or other properties, you have to implement a custom DataTemplateSelector and a data template for each representation, e.g.:
<DataTemplate x:Key="KonfTanimFalseTemplate">
<TextBlock Text="{Binding LISTE_URUN}"/>
</DataTemplate>
<DataTemplate x:Key="KonfTanimTrueTemplate">
<WrapPanel Orientation="Horizontal" MaxWidth="450">
<TextBlock Text="{Binding Path=yeni_ModelTanim}"/>
<TextBlock Text="{Binding Path=MT4}" Tag="{Binding Path=monStd4}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT5}" Tag="{Binding Path=monStd5}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT6}" Tag="{Binding Path=monStd6}" Style="{StaticResource cfgText}"/>
</WrapPanel>
</DataTemplate>
The data template selector checks the konfTanim property and returns the appropriate data template.
public class KonfTanimDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (!(container is FrameworkElement frameworkElement) || !(item is YourItemType yourItem))
return null;
var dataTemplateName = yourItem.konfTanim ? "KonfTanimTrueTemplate" : "KonfTanimFalseTemplate";
return (DataTemplate) frameworkElement.FindResource(dataTemplateName);
}
}
You could also pass in the template names via properties to avoid hard-coding them here. This can help to reuse the selector in your application. In your DataGrid, you could add the data templates to the Resources with an instance of the selector and use it in the template column like this:
<DataGrid ItemsSource="{Binding YourItemTypeList}" AutoGenerateColumns="False">
<DataGrid.Resources>
<DataTemplate x:Key="KonfTanimFalseTemplate">
<TextBlock Text="{Binding LISTE_URUN}"/>
</DataTemplate>
<DataTemplate x:Key="KonfTanimTrueTemplate">
<WrapPanel Orientation="Horizontal" MaxWidth="450">
<TextBlock Text="{Binding Path=yeni_ModelTanim}"/>
<TextBlock Text="{Binding Path=MT4}" Tag="{Binding Path=monStd4}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT5}" Tag="{Binding Path=monStd5}" Style="{StaticResource cfgText}"/>
<TextBlock Text="{Binding Path=MT6}" Tag="{Binding Path=monStd6}" Style="{StaticResource cfgText}"/>
</WrapPanel>
</DataTemplate>
<local:KonfTanimDataTemplateSelector x:Key="KonfTanimDataTemplateSelector"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn CellTemplateSelector="{StaticResource KonfTanimDataTemplateSelector}"/>
</DataGrid.Columns>
</DataGrid>
Isn't there any other way I can do this just using XAML (without C#)?
There is not really anything bad about having a data template selector for complex conditions.
Choosing a DataTemplate Based on Properties of the Data Object
However, often having a flag to determine the type of an object is a sign that the corresponding class should be split into two different types. In this case, you could create a data template with a specific DataType for both types. Unfortunately, automatic data template selection by type works in other items controls, but in DataGrid or more specifically a template column, you would have to use workarounds, which might be more cumbersome than to just create a selector that might as well be reusable in other columns.
Hi I need to solve a problem between the TextBox and the treeview. When I select the TreeView after the TextBox I don't receive the LostFocus Event (for the TextBox) why?
I have tried to play a lot with Focusable and the focusableManager but .... it didn't helped me.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Visibility="{Binding VariableA, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToHiddenConverter}}
<TextBox Width="78" FocusManager.IsFocusScope="True"
PreviewTextInput="HatchingDistanceBox_PreviewTextInput"
Name="TextBoxAWhoShouldLostFocus" BorderThickness="0.5"
BorderBrush="White" MinHeight="30" Height="30" Text="{Binding SelectedFamille.VariableA}"
utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text">
</TextBox>
<TreeView Name="TreeView_After" ItemsSource="{Binding FirstGeneration}" Focusable="True" Grid.ColumnSpan="3" Grid.Row="2" Grid.Column="0" AllowDrop="True" Background="#282828" Margin="15, 0,0,0" >
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<EventSetter Event="GotFocus" Handler="TreeViewItem_GotFocus"></EventSetter>
</Style>
</TreeView.Style>
<i:Interaction.Behaviors>
<utilities:TreeViewSelectionBehavior SelectedItem="{Binding SelectedFamille}"/>
</i:Interaction.Behaviors>
<TreeView.Resources>
<DataTemplate x:Key="NormalTemplate">
<StackPanel Orientation="Horizontal" Name="StrategyNamePanel" Mouse.PreviewMouseDown="StrategyNamePanel_MouseDown" Width="200" Background="#282828" Focusable="True" FocusManager.IsFocusScope="True">
<TextBox Name="StrategyNameBox" FontWeight="Normal" FocusManager.IsFocusScope="True" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=Explicit}" MinHeight="30" Height="30" BorderThickness="0" utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"></TextBox>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EditTemplate">
<StackPanel Orientation="Horizontal" Name="NamePanel" Focusable="True" Mouse.PreviewMouseDown="NamePanel_MouseDown" Width="200" Background="{StaticResource DarkGrey}" FocusManager.IsFocusScope="True">
<TextBox Name="NameBox" FontWeight="Normal" BorderBrush="{StaticResource DarkOrange}" FocusManager.IsFocusScope="True" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=Explicit}" MinHeight="30" Height="30" utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text" ></TextBox>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="GotFocus" Handler="TreeViewItem_GotFocus"></EventSetter>
<EventSetter Event="TreeViewItem.DragOver" Handler="TreeView_After_DragOver"/>
<EventSetter Event="TreeViewItem.Drop" Handler="TreeView_After_Drop"/>
<EventSetter Event="TreeViewItem.MouseMove" Handler="TreeView_After_MouseMove"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
The LostFocus from the textbox work when I click everywhere except in the TreeView
2) The lostFocus work if I first select a parent in the treeView and then a Treeview Item.
3)When I first select a treeViewItem and Then an Another treeViewItem there is no more LostFocus Event.
Why????
I'm working on a project and as redundant as it is - I'm trying to do it entirely without code-behind.
I have a User Control called MessagePanel that's meant to wrap messages received through the TCP connection.
Messages can either be text-only or image-only and my control is meant to handle both using different data templates.
Template for texts:
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Template for images:
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Image}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm having an issue figuring out how to trigger for either of them to be used based on a IsImage boolean property.
I would appreciate any help.
There are several ways to achieve this, and you would typically use a DataTemplateSelector that is assigned to the ItemsControl's Item​Template​Selector property.
You may however write a XAML-only solution with a DataTrigger in the ItemContainerStyle of the ItemsControl:
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsImage}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Image}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Note that you might probably not need to have an IsImage property. The DataTrigger could as well check the Image property for null:
<DataTrigger Binding="{Binding Image}" Value="{x:Null}">
I have created a listview with databinding and a "Itemstemplate" which takes a "Datatemplate" where I have a Stackpannel but the style doesn't apply to the stackpannel, there is no space between the textblocks in the stackpannel:
<ListView Grid.Row="1" DataContext="{Binding Source={StaticResource ViewModel}}" ItemsSource="{Binding}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Gray" >
<StackPanel.Resources>
<Style TargetType="TextBlock" x:Key="margintextblock">
<Setter Property="Margin" Value="10,0,0,0"/>
</Style>
</StackPanel.Resources>
<TextBlock Style="{StaticResource listviewtextblock}" Text="{Binding Path=Firstname}" Foreground="Gold"></TextBlock>
<TextBlock Style="{StaticResource listviewtextblock}" Text="{Binding Path=Lastname}" Foreground="Black"></TextBlock>
<TextBlock Style="{StaticResource listviewtextblock}" Text="{Binding Path=Id}" Foreground="OrangeRed"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
So what's wrong?
You have to remove x:Key="margintextblock" because of this the style doesn't apply automatically to the TextBlocks
By setting the x:Key property on a style, you are telling WPF that you only want to use this style when you explicitly reference it on a specific control.
Take a look on this tutorial
EDITED
And you also have another problem - you are setting style for you TextBlocks Style="{StaticResource listviewtextblock}"
In this case what you have to do is inherit StackPanel TextBlock style from listviewtextblock style
<StackPanel.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource listviewtextblock}">
<Setter Property="Margin" Value="10,0,0,0"/>
</Style>
</StackPanel.Resources>
And remove style Style="{StaticResource listviewtextblock}" from TextBlocks
you code should looks like this
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Gray" >
<StackPanel.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource listviewtextblock}" >
<Setter Property="Margin" Value="10,0,0,0"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="{Binding Path=Firstname}" Foreground="Gold"></TextBlock>
<TextBlock Text="{Binding Path=Lastname}" Foreground="Black"></TextBlock>
<TextBlock Text="{Binding Path=Id}" Foreground="OrangeRed"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
How can I expand all nodes in this code?
<TreeView ItemsSource="{Binding Path=.}" Height="220" HorizontalAlignment="Left" Margin="224,0,0,0" Name="treeView1" VerticalAlignment="Top" Width="162">
<TreeView.ItemTemplate >
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsChecked}" Focusable="False" Uid="{Binding Path=Id}" Click="CheckBox_Click"/>
<TextBlock Text="{Binding Path=Name}" Uid="{Binding Path=Id}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You can have one boolean property e.g. IsExapnded on your class which gets binded with tree view item. Set the default value of IsExapnded to true and bind this with IsExpanded property of treeview item.
It will expand all the nodes.
OR if you want handle only in xaml, you can write like this :
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Use this:
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>