How to set ContentPresenter default content to Unset in WPF XAML - wpf

I'm trying to display status icons in status bar. The icons are defined as ViewBox static resources and displayed via ContentPresenter style with DataTriggers.
I would like no icon displayed if none of the triggers are matched, so I've tried setting the default Setter Content to x:Null or an empty string or remove the line at all, but the other icons stop displaying at all then.
Any ideas please?
My XAML code is as follows
<StatusBarItem Grid.Column="2">
<ContentPresenter>
<ContentPresenter.Style>
<Style TargetType="ContentPresenter">
<Setter Property="Content" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=State}" Value="Ok">
<Setter Property="Content" Value="{StaticResource StatusOK}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=State}" Value="Invalid">
<Setter Property="Content" Value="{StaticResource StatusInvalid}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=State}" Value="Warning">
<Setter Property="Content" Value="{StaticResource StatusWarning}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</StatusBarItem>
Update
I've tried using visibility as suggested by Ed Plunkett but the icons stopped showing up at all. Here is the code.
<Style TargetType="ContentPresenter">
<Setter Property="Content" Value="{StaticResource StatusOK}"/>
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=State}" Value="Ok">
<Setter Property="Content" Value="{StaticResource StatusOK}"/>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=State}" Value="Invalid">
<Setter Property="Content" Value="{StaticResource StatusInvalid}"/>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=State}" Value="Warning">
<Setter Property="Content" Value="{StaticResource StatusWarning}"/>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>

Your problem was misusing a ContentPresenter. There's no reason to use a ContentPresenter outside of a ControlTemplate. The only features it has which differ from ContentControl are things that only make sense inside a ControlTemplate. Now, as it happens, StatusBarItem is a subclass of ContentControl, so you could just style the StatusBarItem and set its Content. Either version in your question will work that way.

Related

Eliminate duplicate DataTrigger logic

I have a status bar that, via data binding and triggers, shows whether a user is connected to a server. I'm styling two different elements to achieve this: the actual StatusBarItem to set a colored background (red, green, yellow), and a TextBlock inside to display the text ("Not Connected", "Connected" etc.) As I'm doing this in XAML, I have to duplicate the DataTrigger logic across two styles (to update the background in one and text in another), like so:
<StatusBarItem Grid.Column="0" HorizontalAlignment="Left" Padding="10,0,10,0">
<StatusBarItem.Style>
<Style TargetType="StatusBarItem">
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Background" Value="Goldenrod" />
</DataTrigger>
</Style.Triggers>
</Style>
</StatusBarItem.Style>
<TextBlock Width="Auto" Height="Auto">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Not Connected" />
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Text" Value="Not Connected" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Text" Value="Connected to Perforce" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Text" Value="Offline Mode" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StatusBarItem>
Question: is there a way to compress this code and not duplicate the DataTrigger logic?
Please note that I'm not interested in solutions that make the TextBlock fill out the entire StatusBarItem. Sure, that would solve this particular issue (I'd just style the TextBlock for both background color and text). But it doesn't address the issue at large (duplicate code that has to be updated in two places).
In this particular case you could set the Content property using the DataTriggers in the StatusBarItem style instead of using an explicit TextBlock as the Content:
<StatusBarItem Grid.Column="0" HorizontalAlignment="Left" Padding="10,0,10,0">
<StatusBarItem.Style>
<Style TargetType="StatusBarItem">
<Setter Property="Background" Value="Red" />
<Setter Property="Content" Value="Not Connected" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.NotConnected}">
<Setter Property="Background" Value="Red" />
<Setter Property="Content" Value="Not Connected" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.Connected}">
<Setter Property="Background" Value="Green" />
<Setter Property="Content" Value="Connected to Perforce" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ConnectionStatus}" Value="{x:Static local:EConnectionStatus.OfflineMode}">
<Setter Property="Background" Value="Goldenrod" />
<Setter Property="Content" Value="Offline mode" />
</DataTrigger>
</Style.Triggers>
</Style>
</StatusBarItem.Style>
</StatusBarItem>
Another option would be to define your own custom ControlTemplate for the StatusBarItem and use ControlTemplate.Triggers to change the background and the text in one place.

Change ListView item base on condition

I have ListView with my object and one of my object properties is of bool value:
<GridViewColumn Width="100" Header="FileCheck " DisplayMemberBinding="{Binding IsFileOK}" />
Instead of displaying this variable value (true or false) how can I replace this with my own text and my own color ?
For example:
File is OK // green color
File damage // red color
This is what i have try:
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFileOK}" Value="false">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFileOK}" Value="true">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
Try this one
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFileOK}" Value="False">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFileOK}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
Idea is to modify the background and text using Style and Triggers.
e.g.
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="Blue"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.Resources>
So you can replace Trigger with DataTrigger to use properties from view model.
Use below code to achieve this,
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="Blue"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsFileOK}" Value="True">
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>

wpf vb.net Datagrid image in row depending on value in cell

This is the code i use but it is notworking
<Window.Resources>
<Style x:Key="PinkRow" TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Rank}" Value="Master">
<Setter Property="Source" Value="A_Cancel.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding RANK}" Value="Bosun">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding RANK}" Value="">
<Setter Property="Background" Value="yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
If field rank has the value "Master" i want the image A_cancel.png
The C# is case sensitive, so the Rank and RANK are different properties. Use proper property name in your bindings. Also you must mention in your Setter the TargetName for Image element.
<DataTrigger Binding="{Binding Rank}" Value="Master">
<Setter TargetName="ImageElementName" Property="Source" Value="A_Cancel.png"/>
</DataTrigger>

WPF DataTrigger to set the Width Window property

I want to set the width property of Window depending on the value of a ViewModel property. First I have a ContentControl:
and then:
<DataTemplate DataType="{x:Type massedit:SimpleFieldVM}">
<ContentControl Content="{Binding .}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<Style.Triggers>
<!-- Without selector, only with DataTriggers select my ContentControl -->
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.ENum}">
<Setter Property="ContentTemplate" Value="{StaticResource ComboboxEnumTemplate}" />
<Setter Property="Width" Value="100"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.List}">
<Setter Property="ContentTemplate" Value="{StaticResource ComboboxListTemplate}" />
<Setter Property="Width" Value="100"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.Bit}">
<Setter Property="ContentTemplate" Value="{StaticResource BitTemplate}" />
<Setter Property="Width" Value="100"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.Date}">
<Setter Property="ContentTemplate" Value="{StaticResource DateTemplate}" />
<Setter Property="Width" Value="150"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.DatTime}">
<Setter Property="ContentTemplate" Value="{StaticResource DatTimeTemplate}" />
<Setter Property="Width" Value="150"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding TargetFieldType}" Value="{x:Static eva:FieldDataType.Time}">
<Setter Property="ContentTemplate" Value="{StaticResource TimeTemplate}" />
<Setter Property="Width" Value="50"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
But change the property Width of my ContentControl. I want to change the property Width of my Window!
You can bind Window.Width directly or you could use FitToContent property.
http://msdn.microsoft.com/en-us/library/vstudio/ms743733%28v=vs.100%29.aspx
FitToContent will try to fit the Window to its content means if you manage to set the content to desired size the window will follow. :)

WPF listview. How to support simultaneously row background color and alternateIndex for this row

I have a listview that contains log messages. I want to set the background color for each row in listview according to the severity of its corresponding entry. I do this using DataTrigger (see the example).
I would also like to support AlternationIndex for listview.
How can I combine them in xaml DataTrigger abd Trigger for background color of row?
For set background color for row I use the following code:
<ListView ... >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Severity} Value="Info">
<Setter
Property="Background"
Value="{Binding Path=Severity,
Converter=
{StaticResource msgSeverityToColorConverter}}"
/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Severity} Value="Error">
<Setter
Property="Background"
Value="{Binding Path=Severity,
Converter=
{StaticResource msgSeverityToColorConverter}}"
/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
And for AlternateIndex I have the following code:
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightBlue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightGray"></Setter>
</Trigger>
</Style.Triggers>
I need that when row with message is not Info or Error, it will be of color from AlternationIndex property.
It's all due to order of declarations of triggers. First declare the alternation triggers and then the severity triggers.
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightBlue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightGray"></Setter>
</Trigger>
<DataTrigger Binding="{Binding Path=Severity} Value="Info">
<Setter Property="Background"
Value="{Binding Path=Severity,
Converter="{StaticResource msgSeverityToColorConverter}}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Severity} Value="Error">
<Setter Property="Background"
Value="{Binding Path=Severity,
Converter="{StaticResource msgSeverityToColorConverter}}" />
</DataTrigger>
</Style.Triggers>

Resources