I have a WPF that uses a TreeView and a HierarchiacalDataTemplate. When I set styling for the different levels, sometimes the foreground color for the text is White and sometimes its Black (depending on the background color). Here's my dilemma. When the user selects an item in the treeview, wpf applies a border (which is fine) and changes the foreground color of the text. For the items that already have a white foreground, its fine but for the items that have a black foreground the text virtual disappears. I can't really use property setters and triggers because the style doesn't apply universally to all nodes, just to certain ones. How can I disable WPF from changing the foreground color at all OnSelection? Below is my WPF code:
<TreeView Name="tvwConfig" VerticalAlignment="Stretch" DockPanel.Dock="Left" Width="300" Background="LightGray" ItemsSource="{Binding}" SelectedItemChanged="Treeview_SelectedItemChanged" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type cfg:AppConfig}" ItemsSource="{Binding Path=Services}">
<Border Width="200" BorderBrush="DarkBlue" Background="DarkBlue" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=ServerName}" FontWeight="Bold" Foreground="White" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type cfg:Service}" ItemsSource="{Binding Path=Queues}">
<Border Width="200" BorderBrush="RoyalBlue" Background="RoyalBlue" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="White" />
<TextBlock Text=" (" FontWeight="Bold" Foreground="White" />
<TextBlock Text="{Binding Path=Modality}" FontWeight="Bold" Foreground="White" />
<TextBlock Text=")" FontWeight="Bold" Foreground="White" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type cfg:Queue}" ItemsSource="{Binding Path=Statuses}">
<Border Width="200" BorderBrush="AliceBlue" Background="AliceBlue" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Path=Name}" FontWeight="SemiBold" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type cfg:Status}">
<Border Width="200" BorderBrush="White" Background="White" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Path=Weight}" />
<TextBlock Text=")" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I'm not able to test this right now, but I think you should be able to define your Style in an ItemContainerStyle for your HierarchicalDataTemplate and define the style (with setters) in each one as required.
E.g (from one of your examples):
<HierarchicalDataTemplate DataType="{x:Type cfg:AppConfig}" ItemsSource="{Binding Path=Services}">
<!-- Example -->
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Foreground" Value="DarkOrange" />
<!-- Triggers if required -->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="DarkOrange" />
</Trigger>
<!-- DataTriggers if required -->
<DataTrigger Binding="{Binding Path=SomeProperty}" Value="SomeValue">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<!-- End Example -->
<Border Width="200" BorderBrush="DarkBlue" Background="DarkBlue" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=ServerName}" FontWeight="Bold" Foreground="White" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
The IsSelected setter should help you sort out the foreground colours.
Set this style in Resources. Don't set any key it will be applied for all the TreeViewItems that satisfy the condition.
Sample code:
<Style TargetType="TreeViewItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Related
how do make a letter pop out of the border?
I want to express it like this picture
I wrote a letter in the text on Border,
The letters are covered like in the picture.
Can you make this stick out like the picture below?
How can solve this?
this is my xaml code
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject"
Width="800"
Height="600"
Title="ItemsControl 엘리먼트 : Template/ItemsPanel/ItemTemplate/ItemContainerStyle 속성 사용하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Window.Resources>
<local:TaskCollection x:Key="TaskCollectionKey" />
</Window.Resources>
<Grid>
<ItemsControl
HorizontalAlignment="Center"
VerticalAlignment="Center"
ItemsSource="{Binding Source={StaticResource TaskCollectionKey}}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border
BorderBrush="Black"
BorderThickness="3"
CornerRadius="15">
<ItemsPresenter />
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataTemplate.Resources>
<Grid>
<Ellipse
Stroke="Black"
StrokeThickness="3"
Fill="Gold" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock
Margin="5"
Text="{Binding Path=Priority}" />
<TextBlock
Margin="5"
Text="{Binding Path=TaskName}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Margin" Value="10" />
<Setter Property="Control.Width" Value="100" />
<Setter Property="Control.Height" Value="100" />
<Style.Triggers>
<Trigger
Property="Control.IsMouseOver" Value="True">
<Setter Property="Control.ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=Content.Description}" />
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</Window>
If you put the textblock in a canvas, that will not clip.
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock
Margin="5"
Text="{Binding Path=Priority}" />
<Canvas>
<TextBlock
Text="{Binding Path=TaskName}" />
</Canvas>
</StackPanel>
I have the following usercontrol:
<Border
Style="{StaticResource notificationBarBorderStyle}"
Height="21"
>
<StackPanel
Orientation="Horizontal"
Style="{StaticResource notificationBarStyle}"
>
<DockPanel>
<Image
Width="17"
Height="16"
Margin="4,0,11,0"
Source="{Binding ElementName=NotificationControl, Path=ImageSource}"
/>
<TextBlock
x:Name="notificationTextBlock"
VerticalAlignment="Center"
Style="{StaticResource textBlockStyle}"
Text="{Binding ElementName=NotificationControl, Path=Message}"
/>
</DockPanel>
</StackPanel>
</Border>
and then in another usercontrol i try to reference it like so:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}"
ImageSource="{DynamicResource somePicture1}"
>
I want to be able to put a data trigger on the image source so that depending on the state of a boolean flag, a different image will appear (call it somePicture2). I do not really want to do much to change the control itself, as it is referenced a few times in a rather large project and I do not want to break anything.
You could set the Style property of the control to a Style with a DataTrigger that binds to your bool property:
<Controls:NotificationBarControl
Grid.Row="2"
Grid.Column="0"
DataContext="{Binding IncomingResult}"
Message="{Binding TaskResultsMessage}"
Visibility="{Binding Path=ShowTaskResults, Converter={StaticResource boolToHiddenVisibilityConverter}}"
Command="{Binding DisplayTaskError}">
<Controls:NotificationBarControl.Style>
<Style TargetType="Controls:NotificationBarControl">
<Setter Property="ImageSource" Value="{StaticResource somePicture1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding YourBooleanSourceProperty}" Value="True">
<Setter Property="ImageSource" Value="{StaticResource somePicture2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Controls:NotificationBarControl.Style>
</Controls:NotificationBarControl>
I got a TabControl with two TabItems, I created a template for it.
<TabControl x:Name="MainInfoTabControl" Grid.Row="3" Grid.RowSpan="7" Grid.Column="0" Grid.ColumnSpan="2"
Background="{x:Null}"
BorderBrush="{x:Null}"
>
<TabControl.Resources>
<Style x:Key="TabHeaderStyle" TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="FontWeight" Value="DemiBold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="HeaderBorder" BorderBrush="White" BorderThickness="2" CornerRadius="10,10,0,0" >
<TextBlock Text="" VerticalAlignment="Center" Margin="5"></TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Header="Main Details"
Margin="0.5, 0.5, 0, 0.5"
FontSize="15"
MinHeight="40" Width="200"
Style="{StaticResource TabHeaderStyle}"
>
</TabItem>
<TabItem Header="Pets Owned"
Margin="0.5, 0.5, 0, 0.5"
FontSize="15"
MinHeight="40" Width="200"
Style="{StaticResource TabHeaderStyle}"
>
</TabItem>
</TabControl>
The problem is the tabItem's Header doesn't show up. In my template there is a TextBlock but i couldn't customize the TextBlock.Text dynamically (atleast bind or somewhat change the Text property during run time)
TabItem1 should be "Owner Details" while TabItem2 should be "Pets Owned"
You override default tabitem template you need to get somehow to parent's value.
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Header}"
VerticalAlignment="Center"
Margin="5">
</TextBlock>
or
<TextBlock Text="{TemplateBinding Property=Header}"
VerticalAlignment="Center"
Margin="5">
</TextBlock>
I am working on a C# WPF project and I have a list view which uses data binding and a collection view.
Below is how my ListView is currently populated.
<ListView HorizontalAlignment="Left" Margin="547,12,0,41" Name="lstCallLogInformation" Width="320">
<ListView.Style>
<Style TargetType="ListView">
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<TextBlock Text="No items in your devices call log" FontWeight="Bold" HorizontalAlignment="Center" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Foreground="Gray" Text="{Binding Name}" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel Style="{StaticResource onmouseover}">
<StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal" Tag="{Binding logID}">
<Image Height="30" Source="{Binding base64ImageString, Converter={StaticResource ImageConverter}}" Width="30" />
<StackPanel Margin="10" Orientation="Vertical">
<TextBlock FontWeight="Bold" Text="{Binding contactNameOrPhoneNumber}" />
<StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" Text="{Binding dateString}" />
<TextBlock Margin="15, 0, 0, 0" Text="Duration: " />
<TextBlock HorizontalAlignment="Right" Text="{Binding humanReadableCallDuration}" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical">
<Button Background="Transparent" BorderThickness="0" BorderBrush="Transparent" Tag="{Binding logID}" Name="btnAddAsContact" Click="btnAddAsContact_Click">
<Image Width="15" Height="15" Source="/BoardiesSMSServer;component/images/add.png" Tag="{Binding logID}" />
</Button>
<Button Background="Transparent" BorderThickness="0" BorderBrush="Transparent" Tag="{Binding logID}" Name="btnDeleteContactFromLog" Click="btnDeleteContactFromLog_Click">
<Image Width="15" Height="15" Source="/BoardiesSMSServer;component/images/delete.png" Margin="0,0,0,5" Tag="{Binding logID}" />
</Button>
</StackPanel>
</StackPanel>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Within my DockPanel within the DataTemplate I have a StackPanel which contains various TextBlocks from the array that is passed into the binding.
In one of the StackPanels you will see you will see a TextBlock that binds to the element of contactNameOrPhoneNumber.
What I want to be able to do is if another value from the binding is null then I add a TextBlock for the contactNameOrPhoneNumber` element and alongside it have another TextBlock which contains another element of number``, if the other binding value is not null then this extra textblock of number is not added.
So in simple terms, what I want to be able to do is within the DataTemplate have a conditional if statement of if binding value == null add textblock to stackpanel else don't add textblock.
You can do that with Style + Triggers something like this:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding PropertyName}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Also you can create IValueConverter say ObjectToVisibilityConverter which will take input your property and if property is null return Visibility.Collapsed else return Visibility.Visible.
You can then bind property with Visibility value of TextBlock via Converter.
<TextBlock Visibility="{Binding PropertyName,
Converter={StaticResource ObjectToVisibilityConverter}}"/>
I have two things I'm trying to achieve:
Add a horizontal separator between listbox items in WPF.
Don't show the separator at the bottom of the final listbox item.
My current layout is pictured here:
This shows 2 listbox items (though I have no way of knowing how many items could potentially be generated). I would like them separated by a horizontal separator, except on the last listbox item so there isn't a spare separator at the bottom of the pane. How can I achieve this in XAML? See my current XAML here:
<TabItem Header="Third Party Updates">
<Grid>
<TextBlock Name="ThirdPartyNoManifestTextBox" Width="Auto" HorizontalAlignment="Left" Margin="267,22,0,0" TextWrapping="Wrap" Text="{Binding Path=WindowsUpdateCompliance, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" FontSize="14" Foreground="DarkSlateBlue"/>
<Button Name="CheckforThirdPartyUpdatesButton" Content="Check for Third Party Updates" Margin="10,11,339,304" Click="CheckforThirdPartyUpdatesButton_Click" MaxWidth="200" Grid.Column="1" Grid.Row="1"/>
<ListBox Name="ThirdPartyListBox" ItemsSource="{Binding}" Margin="0,70,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="PostponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="•" Grid.Row="1" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="2" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="3" VerticalContentAlignment="Center"/>
<Label Content="•" Grid.Row="4" VerticalContentAlignment="Center"/>
<StackPanel Orientation="Horizontal" Grid.Column="1">
<Label Name="MissingRequiredAppGenericTextBlock" VerticalAlignment="Center" Content="Required application update detected:" FontWeight="SemiBold" FontSize="12"/>
<Label Name="RequiredAppNameTextBlock" VerticalAlignment="Center" Content="{Binding Item2.Name}" Foreground="MidnightBlue" FontSize="13"/>
<Label Grid.Column="1" Grid.Row="1" Name="RequiredAppVersionTextBlock" Content="{Binding Item2.RequiredVersion}" VerticalAlignment="Center" Foreground="MidnightBlue" FontSize="13"/>
</StackPanel>
<TextBlock Grid.Column="1" Grid.Row="1" Name="RequiredAppCustomUIMessageTextBlock" Text="{Binding Item2.CustomUIMessage}" TextWrapping="Wrap" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="2" VerticalAlignment="Center">
<Hyperlink Name="Link" NavigateUri="{Binding Item2.TT}" RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="{Binding Item2.TT}"/>
</Hyperlink>
</TextBlock>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3">
<TextBlock Text="The following processes will be closed prior to install: " VerticalAlignment="Center" />
<TextBlock Text="{Binding Item2.ListOfProcessesToClose}" FontWeight="SemiBold" Foreground="Red" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="4">
<TextBlock Text="You have used " VerticalAlignment="Center" />
<TextBlock Text="{Binding Item3.UsedDeferrals}" VerticalAlignment="Center"/>
<TextBlock Text=" of " VerticalAlignment="Center"/>
<TextBlock Text="{Binding Item2.MaxDefferals}" VerticalAlignment="Center"/>
<TextBlock Text=" deferrals for this update." VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding PostponeClicked}" Value="1">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
<Trigger Property="Control.IsMouseOver" Value="True">
<Setter Property="Control.BorderBrush" Value="SteelBlue" />
<Setter Property="Control.BorderThickness" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</TabItem>
Update
Added suggested separator code. Separator is now present but does not fill the available horizontal space:
You can try to put Separator at the top of each item. With that you don't have unwanted Separator after the last item.
Then use DataTrigger with {RelativeSource PreviousData} binding to hide separator at the top of the first item :
<StackPanel>
<Separator>
<Separator.Style>
<Style TargetType="Separator">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Separator.Style>
</Separator>
<StackPanel Orientation="Horizontal">
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Click ="PostponeThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Grid>
.........
.........
</Grid>
</StackPanel>
</StackPanel>
UPDATE :
I can't tell for sure what causes the separator not stretching accross listbox width. Maybe try to set listboxitem's HorizontalContentAlignment to Stretch :
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>