This is my binding data:
List<MyData> files;
public clas MyData
{
public string Name { get; set; } // Column
public bool IsOK { get; set; } // Not a Column
public string Format { get; set; } // Column
}
My ListView:
<ListView
Grid.Row="0"
Name="lvFiles"
ItemsSource="{Binding wiresharkFiles}">
<ListView.ItemContainerStyle>
<DataTrigger Binding="{Binding IsOK}" Value="True">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Background" Value="Green"/>
</MultiTrigger>
</ListView.ItemContainerStyle>
And i have several ListViewColumns because i want to change the color of only the Name column i added this to my other column (Format column) GridViewColumn:
<GridViewColumn Width="115" Header="Format">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
x:Name="textBlock"
Text="{Binding FileFormat}"
Margin="0,0,0,0"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsOK}" Value="True">
<Setter TargetName="textBlock" Property="Foreground" Value="Silver"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
This not mark this Column (format column) in red but in case IsMouseIsOver is true this column is still in Silver and not become White like define in my trigger.
So i changed my GridViewColumn to this:
<GridViewColumn Width="115" Header="Format">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
x:Name="textBlock"
Text="{Binding FileFormat}"
Margin="0,0,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding BadCheckSumExist}" Value="True">
<Setter TargetName="textBlock" Property="Foreground" Value="Silver"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
But this still not works as expected.
Keep your triggers in ItemContainerStyle. Just add Foreground binding to TextBlock that will take foreground brush from ListViewItem's Foreground.
<TextBlock x:Name="textBlock"
Text="{Binding FileFormat}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Margin="0,0,0,0"/>
Related
I have a List<object> which contains a list of of values for each object which I want to access and create a set image based on the values - don't really want to use a Converter.
I have the below which works:
<Image x:Name="Desk1" Grid.Column="1" Grid.Row="2" Width="50" Height="50">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
But I don't want to have to write all this for many desks.
So I've created a Resource:
<Windows.Resources>
<DataTemplate x:Key = "DeskImage">
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Windows.Resources>
Which I was hoping to access for each image and just pass it the value in Office[x].Desk[x].Status to determine which image to load. But this is the bit I'm unsure on how to create an image type in xaml and pass the value to the static resource.
Something like:
<Image x:Name="Desk1" Grid.Column="1" Grid.Row="2" Width="50" Height="50">
[pseudocode]
Bind to Office[x].Desks[x].Status
Pass data to Resource and load correct image
[/pseudo]
</image>
You may consider using nested ItemsControls.
<ItemsControl ItemsSource="{Binding Office}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Desks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Width="50" Height="50">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm struggeling with binding a datatrigger to a textblock property. I have added a working Datatrigger example in the TextBox.
The issue is the TextBlock DataTrigger I can not get working. At startup IsNameActive has value 'false' and BackGround is PaleVioletRed, but it does not change when IsNameActive changes.
public bool IsNameActive
{
get => !string.IsNullOrEmpty(FirstName);
}
public string FirstName
{
get => _firstName;
set
{
if (value != _firstName)
{
_firstName = value;
OnPropertyChanged(FirstName);
OnPropertyChanged(IsNameActive);
}
}
}
<TextBox
Grid.Row="0"
Grid.Column="1"
Margin="15"
Text="{Binding UpdateSourceTrigger=PropertyChanged, Path=FirstName, ValidatesOnDataErrors=true, NotifyOnValidationError=true}">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Background" Value="RosyBrown" />
<Style.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="aa">
<Setter Property="Background" Value="DarkOliveGreen" />
</DataTrigger>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="">
<Setter Property="Background" Value="CornflowerBlue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBlock
Grid.Row="2"
Grid.Column="1"
Margin="15"
Text="TextBlock with binding">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataContext.IsNameActive, RelativeSource={RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Background" Value="CornflowerBlue" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataContext.IsNameActive, RelativeSource={RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}" Value="false">
<Setter Property="Background" Value="PaleVioletRed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
As #Ash pointed out in the comment section, you need to wrap nameof around IsNameActive when you call OnPropertyChanged:
OnPropertyChanged(nameof(IsNameActive));
I tried to bind to IsExpanded property in Hierarchical template with another context.
<HierarchicalDataTemplate x:Key="TreeView1" ItemsSource="{Binding Path=Folders}" >
<StackPanel Margin="5,5,5,5" Orientation="Horizontal">
<StackPanel Name="spinCont">
<ModulesUpToDateChecker1:Spinner Width="20" x:Name="Spin" FolderContext="{Binding}" StateContext="{Binding Path=State}"></ModulesUpToDateChecker1:Spinner>
<Image x:Name="imgFolderIcon" Width="16" Visibility="Hidden"
Source="/ModulesUpToDateChecker;component/Resources/FolderClosed16.png">
<Image.Triggers>
</Image.Triggers>
</Image>
<Image VerticalAlignment="Center" x:Name="imgFolderItem"
Source="{Binding Path=State, Converter={StaticResource stateFolderConverter}}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsLast}" Value="true"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Collapsed"></Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
<StackPanel DataContext="{Binding Path=Modules}">
<ModulesUpToDateChecker1:Spinner Width="20">
<ModulesUpToDateChecker1:Spinner.Style>
<Style TargetType="{x:Type ModulesUpToDateChecker1:Spinner}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Animation}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</ModulesUpToDateChecker1:Spinner.Style>
</ModulesUpToDateChecker1:Spinner>
<Image VerticalAlignment="Center"
Source="{Binding Path=State, Converter={StaticResource stateImageConverter}}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Animation}" Value="True" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
<TextBlock Text="{Binding Path=Name}" Margin="10,0,0,0"></TextBlock>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<!--<Trigger Property="{Binding}" Value="true">
<Setter TargetName="imgFolderIcon" Property="Source" Value="/ModulesUpToDateChecker;component/Resources/Error.png" />
</Trigger>-->
**<DataTrigger Binding="{Binding Path=IsExpanded}" Value="true">
<Setter TargetName="imgFolderIcon" Property="Source" Value="/ModulesUpToDateChecker;component/Resources/Error.png" />
</DataTrigger>**
doest work
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
I have the "Folder" context (its hierarchical object) but how can i bind to theTreeView properties in HierarchicalDataTemplate.Triggers? When i start this, output shows that there is no IsExpanded property in Folder object. So, i have wrong context.
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsExpanded}" Value="true">
<Setter TargetName="imgFolderIcon" Property="Source" Value="/Resources/FolderExpanded.png" />
</DataTrigger>
Easy
In my WPF application I have an ObservableCollection of items. Each of item must have a unique name and the name of the item must starts with a letter. I check data validation errors in base class that implements IDataErrorInfo. The problem is that when user enters the existing name the ellipse and the "!" sign appear only in one row, instead of two, but both of them have validation errors. Here is some code of my DataGrid.
<DataGrid ItemsSource="{Binding Path=IconManagerModel.ConfigurationIcons,
ValidatesOnDataErrors=True}" x:Name="IconsData">
<DataGrid.Resources>
<Style x:Key="errorStyle" TargetType="{x:Type TextBlock}" >
<Setter Property="Padding" Value="2"/>
<Style.Triggers>
//Error style for names which not starts with letter
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource=
RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
//Error style for duplicated names
<DataTrigger Binding="{Binding IsDuplicated}" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip" Value="Duplicated Name" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="ErrorEditStyle" TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="2"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
//This template applies only for the row that has been edited.
//Other row with the same IconId keeps default style
<Grid ToolTip="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}" >
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}">
</Ellipse>
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Icon Name">
</DataGridTemplateColumn>
<DataGridTextColumn ElementStyle="{StaticResource ResourceKey=errorStyle}"
EditingElementStyle="{StaticResource ResourceKey=ErrorEditStyle}"
Binding="{Binding IconId, ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"/>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Thanks in advance.
I have an order entry form that has a ListBox with a list of line items. I have my items template, and one of the values is a ComboBox in each of my Items.
Now, my form can also create Credit memo's in addition to purchase orders, but when I am creating a credit memo, I want to put the words "Credit Memo" over the list box, however, the TextBlock covers the ComboBox in two of my line items. I would like to pass my click event through the TextBlock to the ComboBoxes but I'm not sure how to do it.
This is what I have, ( Maybe I am coming at this totally wrong, I am kinda a noob with WPF )
<ListBox SelectionMode="Single" Grid.Row="2"
ItemsSource="{Binding Path=LineItems}" HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True" Background="#66FFFFFF">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsPartBackOrder}" Value="True">
<Setter Property="Background" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Entities:SalesOrderLineItem}" >
<OrderEntry:SalesOrderLineItemCreate DataContext="{Binding}" DeleteSalesOrderLineItem="DeleteSalesOrderLineItem" Margin="0,3,3,0" >
<OrderEntry:SalesOrderLineItemCreate.Resources>
<Style TargetType="{x:Type OrderEntry:SalesOrderLineItemCreate}">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource=
{
RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}
},
Path=IsSelected
}" Value="True">
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</OrderEntry:SalesOrderLineItemCreate.Resources>
</OrderEntry:SalesOrderLineItemCreate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="2"
Text="Credit Memo"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48" Height="Auto"
FontStyle="Italic"
Foreground="Red"
Opacity=".25">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CR">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=OrderType}" Value="CU">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock IsHitTestVisible="False" .../>