How to refactor Events in WPF? - wpf

I have multiple textboxes with TextChanged events bound to the same handler
<TextBox TextChanged="TextBox_TextChanged" />
<TextBox TextChanged="TextBox_TextChanged" />
<TextBox TextChanged="TextBox_TextChanged" />
<TextBox TextChanged="TextBox_TextChanged" />
Is there any way to do something like this?
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox">
<Setter Property="TextChanged" Value="TextBox_TextChanged" />
</Style>
</StackPanel.Resources>
<TextBox />
<TextBox />
<TextBox />
<TextBox />
</StackPanel>
I know the code above is invalid, but it is something similar to what I want to achieve

If I'm not mistaken, you can put the TextBoxBase.TextChanged="TextBox_TextChanged" attribute on the common container element of all of your text boxes, for ex:
<StackPanel TextBoxBase.TextChanged="TextBox_TextChanged">
<TextBox />
<TextBox />
<TextBox />
<TextBox />
</StackPanel>

If you want it in a style:
<Style TargetType="{x:Type TextBox}">
<EventSetter Event="TextChanged" Handler="TextBox_TextChanged"/>
</Style>

Related

How to make Label Text Underline?

How can I make Label text Underline in WPF? I am stucked and could not find any property for underline:
<Label Name="lblUserName"
Content="Username"
FontSize="14" FontWeight="Medium" />
In Label no TextDecorations, therefore try this:
<Label Width="100" Height="30">
<TextBlock TextDecorations="Underline">TestText</TextBlock>
</Label>
Edit: more universal solution
In this case, instead of Label.Content using Label.Tag, because Content property can be set only once:
<Label Tag="TestContent"
Width="100"
Height="30"
HorizontalContentAlignment="Center"
Background="AliceBlue">
<TextBlock TextDecorations="Underline"
Text="{Binding Path=Tag,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Label}}}" />
</Label>
Here's a way to apply the style directly to the Label:
<Style TargetType="Label">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" TextDecorations="Underline"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
This simplifies the label items:
<Label>
Label 1
</Label>
<Label Grid.Row="1">
Label 2
</Label>
This works if the content of the labels text only.
Here's an answer with styles.
Content:
<Label>
<TextBlock Style="{DynamicResource StyleName}">text content</TextBlock>
</Label>
And the style:
<Style x:Key="StyleName">
<Setter Property="TextBlock.TextDecorations" Value="Underline" />
<Setter Property="TextBlock.FontStyle" Value="Italic" />
</Style>

WPF Surface listbox data binding - listbox content not being populated with content

I was using XmlDataProvider to get pictures from a folder, then display them in a list box, but something is wrong that list box appears but without those pictures. Pictures are in a folder called Resources in the project directory.
here are the codes, xmldata part:
<!-- List content -->
<XmlDataProvider x:Key="tri" XPath="Root">
<x:XData>
<Root xmlns="">
<Entry Name="Cone" Image="\Resources\cone.jpg" />
<Entry Name="Cube" Image="\Resources\cube.jpg" />
<Entry Name="Cylinder" Image="\Resources\cylinder.jpg" />
<Entry Name="Icosahedron" Image="\Resources\icosahedron.jpg" />
<Entry Name="Octahedron" Image="\Resources\octahedron.jpg" />
<Entry Name="Sphere" Image="\Resources\sphere.jpg" />
<Entry Name="Torus" Image="\Resources\torus.jpg" />
<Entry Name="YinYang" Image="\Resources\yinyang.jpg" />
</Root>
</x:XData>
</XmlDataProvider>
then the listbox part:
<s:SurfaceListBox x:Name="triList" Grid.Row="1"
s:SurfaceDragDrop.DragCompleted="OntriListDragCompleted"
s:SurfaceDragDrop.DragCanceled="OntriListDragCanceled"
PreviewMouseLeftButtonDown="OntriListPreviewMouseLeftButtonDown"
PreviewMouseMove="OntriListPreviewMouseMove"
PreviewMouseLeftButtonUp="OntriListPreviewMouseLeftButtonUp"
ItemsSource="{Binding Source={StaticResource tri}, XPath=Entry}"
Style="{StaticResource triListStyle}"
PreviewTouchDown="OntriListPreviewTouchDown"
PreviewTouchMove="OntriListPreviewTouchMove"
PreviewTouchUp="OntriListPreviewTouchUp" Height="234" VerticalAlignment="Top" Visibility="Visible" ItemsPanel="{Binding}" AllowDrop="False" />
the list style:
<Style x:Key="triListStyle" TargetType="{x:Type s:SurfaceListBox }">
<Setter Property="Background" Value="{DynamicResource {x:Static s:SurfaceColors.ListBoxItemBackgroundBrushKey}}" />
<Setter Property="SelectionMode" Value="Single" />
<Setter Property="Height" Value="234" />
<Setter Property="ItemTemplateSelector">
<Setter.Value>
<sc:triListTemplateSelector>
<sc:triListTemplateSelector.NormalItemTemplate>
<DataTemplate >
<StackPanel RenderTransformOrigin="0.5, 0.5"
Margin="7,0,0,0"
MinWidth="171" MaxWidth="171"
MinHeight="235" MaxHeight="235">
<Image Margin="14,21,21,11" Source="{Binding XPath=#Image}"
Height="149" Width="101" />
<TextBlock Text="{Binding XPath=#Name}"
MaxWidth="116"
FontSize="12"
Margin="21,0,21,21"
FontFamily="Segoe360"
TextAlignment="Center"
TextWrapping="Wrap"
Foreground="{DynamicResource {x:Static s:SurfaceColors.ListBoxItemForegroundBrushKey}}"
HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</sc:triListTemplateSelector.NormalItemTemplate>
<sc:triListTemplateSelector.StartingItemTemplate>
<DataTemplate>
<Grid Margin="17, 0, 0, -14">
<StackPanel RenderTransformOrigin="0.5, 0.5"
Margin="7,0,0,0"
MinWidth="171" MaxWidth="171"
MinHeight="235" MaxHeight="235">
<Image Margin="14,21,21,11"
Source="{Binding XPath=#Image}"
Height="149"
Width="101" />
<TextBlock Text="{Binding XPath=#Name}"
MaxWidth="116"
FontSize="12"
Margin="21,0,21,21"
FontFamily="Segoe360"
TextAlignment="Center"
TextWrapping="Wrap"
Foreground="{DynamicResource {x:Static s:SurfaceColors.ListBoxItemForegroundBrushKey}}"
HorizontalAlignment="Center" />
</StackPanel>
<Rectangle Fill="{DynamicResource {x:Static s:SurfaceColors.SurfaceWindowBackgroundBrushKey}}"
Width="17" HorizontalAlignment="Left" Margin="-26,-2.5,0,3" />
</Grid>
</DataTemplate>
</sc:triListTemplateSelector.StartingItemTemplate>
</sc:triListTemplateSelector>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<s:SurfaceScrollViewer Background="{TemplateBinding Background}"
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Hidden"
CanContentScroll="True">
<!--<sc:LoopingPanel IsItemsHost="True" /> -->
</s:SurfaceScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
can you help me to find out the problem?
Don't know why you need the XmlDataProvider stuff for showing some images in a ListBox, but what you need is a DataTemplate with an Image control that actually visualizes each image:
<DataTemplate x:Key="imageTemplate">
<Image Source="{Binding XPath=#Image}"/>
</DataTemplate>
You would use that in your ListBox by setting the ItemTemplate property:
<s:SurfaceListBox ... ItemTemplate="{StaticResource imageTemplate}"/>
Also make sure that the Build Action is set to Resource for the image files in your Visual Studio project.

WPF: Formatting a label

I have the following code for an Expander:
<Expander Name="CompanyLinks" Header="{StaticResource companyLinksHeader}"
FontSize="18" FontFamily="Calibri" FontWeight="Bold">
<StackPanel>
<Label Content="{StaticResource companyLinksItemSummary}"
FontSize="14" FontFamily="Calibri" FontWeight="Bold"/>
<Label Content="{StaticResource companyLinksItemInfo}"
FontSize="14" FontFamily="Calibri" FontWeight="Bold"/>
<Label Content="{StaticResource companyLinksItemIssues}"
FontSize="14" FontFamily="Calibri" FontWeight="Bold"/>
<Label Content="{StaticResource companyLinksItemMessages}"
FontSize="14" FontFamily="Calibri" FontWeight="Bold"/>
</StackPanel>
</Expander>
The StaticResources are defined as follows (in my resource dictionary):
<sys:String x:Key="companyLinksHeader">company</sys:String>
<sys:String x:Key="companyLinksItemSummary">summary</sys:String>
<sys:String x:Key="companyLinksItemInfo">info</sys:String>
<sys:String x:Key="companyLinksItemIssues">issues</sys:String>
<sys:String x:Key="companyLinksItemMessages">messages</sys:String>
Is there a way to define a dictionary entry (or something else) that will handle the Font styling for the Header and Labels so that I don't have to define the same font over and over (and only change it in one place should I want to change the font)?
EDIT
I found a solution (thanks to those that posted) and am using the following Style for the StackPanel Label items:
<!-- Expander Items text style -->
<Style x:Key="expanderItemsTextStyle">
<Setter Property="Label.FontFamily" Value="Trebuchet MS"></Setter>
<Setter Property="Label.FontWeight" Value="Normal"></Setter>
<Setter Property="Label.FontSize" Value="14"></Setter>
<Setter Property="Label.Foreground" Value="Aqua"></Setter>
</Style>
and implementing it like this (applying it to the StackPanel so it affects all Labels):
<Expander Name="CompanyLinks" Header="{StaticResource companyLinksHeader}"
Style="{StaticResource expanderHeaderTextStyle}">
<StackPanel Style="{StaticResource expanderItemsTextStyle}">
<Label Content="{StaticResource companyLinksItemSummary}"/>
<Label Content="{StaticResource companyLinksItemInfo}" />
<Label Content="{StaticResource companyLinksItemIssues}" />
<Label Content="{StaticResource companyLinksItemMessages}" />
</StackPanel>
</Expander>
One thing that does not work though is the Label.Foreground. The foreground color remains black but I can change the font, size or weight via the style. If I move the style into the Label definition though the color works. Is this a bug or is there a different property that will set the font color (foreground) of the StackPanel Labels.
You can use a Style within Window.Resources, and refer to this style using BasedOn within the StackPanel.Resources section. This will apply the styles to all labels inside that StackPanel.
<Window>
<Window.Resources>
<Style x:Key="myLabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontSize" Value="14" />
<Setter Property="FontFamily" Value="Calibri" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Window.Resources>
<Expander Name="CompanyLinks" Header="{StaticResource companyLinksHeader}"
FontSize="18" FontFamily="Calibri" FontWeight="Bold">
<StackPanel>
<StackPanel.Resources>
<Style BasedOn="{StaticResource myLabelStyle}" TargetType="{x:Type Label}" />
</StackPanel.Resources>
<Label Content="{StaticResource companyLinksItemSummary}" />
<Label Content="{StaticResource companyLinksItemInfo}" />
<Label Content="{StaticResource companyLinksItemIssues}" />
<Label Content="{StaticResource companyLinksItemMessages}" />
</StackPanel>
</Expander>
</Window>
Use a Style:
<Expander Name="CompanyLinks" Header="{StaticResource companyLinksHeader}"
FontSize="18" FontFamily="Calibri" FontWeight="Bold">
<Expander.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="14" />
<Setter Property="FontFamily" Value="Calibri" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Expander.Resources>
<StackPanel>
<Label Content="{StaticResource companyLinksItemSummary}" />
<Label Content="{StaticResource companyLinksItemInfo}" />
<Label Content="{StaticResource companyLinksItemIssues}" />
<Label Content="{StaticResource companyLinksItemMessages}" />
</StackPanel>
</Expander>
Here the Style targets all Label within Expander.
Declare the Fontsize and Font Name in the Resource file
<FontFamily x:Key="BaseFontFamily">Calibri</FontFamily>
<sys:Double x:Key="BaseFontSize">12</sys:Double>
<Label Content="{StaticResource companyLinksItemMessages}"
FontSize="{StaticResource BaseFontSize}" FontFamily="{StaticResource fntfam}"/>

WPF TextBlock StringFormat Binding To Parent

I have been trying to bind the StringFormat of the Text property of a TextBlock to a templated parent.
Here is where I'm trying to set the StringFormat:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataFlowControls">
<Style TargetType="{x:Type local:DfcEditTextBox}">
<Setter Property="Margin" Value="-6, 0, -6, 0" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DfcEditTextBox}">
<TextBlock x:Name="PART_TextBlock"
Padding="2, 0, 0, 0"
Text="{Binding Path=Value, StringFormat=ThisStringFormat, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Here is the parent:
<Window x:Class="DataFlowControls.Show.DfcListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dfc="clr-namespace:DataFlowControls;assembly=DataFlowControls"
xmlns:local="clr-namespace:DataFlowControls.Show"
Title="DfcListView" Height="400" Width="500">
<Grid>
<StackPanel>
<dfc:DfcListView Name="lvTradesCollection" ItemsSource="{Binding Path=TradesCollection}" KeyboardNavigation.DirectionalNavigation="Continue" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<DataTemplate x:Key="Date_DataTemplate">
<dfc:DfcEditTextBox Value="{Binding Path=Date, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" ThisStringFormat='{}{0:dd/MM/yyyy}' HorizontalContentAlignment="Left" IsEditable="true" />
</DataTemplate>
<DataTemplate x:Key="Asset_DataTemplate">
<dfc:DfcEditTextBox Value="{Binding Path=Asset, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Left" IsEditable="true" />
</DataTemplate>
<DataTemplate x:Key="Lots_DataTemplate">
<dfc:DfcEditTextBox Value="{Binding Path=Lots, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" ThisStringFormat='N2' HorizontalContentAlignment="Center" IsEditable="true" />
</DataTemplate>
<DataTemplate x:Key="Price_DataTemplate">
<dfc:DfcEditTextBox Value="{Binding Path=Price, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Center" IsEditable="true" />
</DataTemplate>
<DataTemplate x:Key="IsCheap_DataTemplate">
<dfc:DfcEditCheckBox Value="{Binding Path=IsCheap, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" IsEditable="true" />
</DataTemplate>
<DataTemplate x:Key="NextTrade_DataTemplate">
<dfc:DfcEditComboBox Value="{Binding Path=NextTrade, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{x:Static local:DfcListView.NextTradeTypes}" IsEditable="true" />
</DataTemplate>
</ListView.Resources>
<ListView.View>
<dfc:DfcGridView>
<dfc:DfcGridViewColumn Header="Date" Width="140" CellTemplate="{StaticResource Date_DataTemplate}" />
<dfc:DfcGridViewColumn Header="Asset" Width="40" CellTemplate="{StaticResource Asset_DataTemplate}" />
<dfc:DfcGridViewColumn Header="Lots" Width="40" CellTemplate="{StaticResource Lots_DataTemplate}" />
<dfc:DfcGridViewColumn Header="Price" Width="50" CellTemplate="{StaticResource Price_DataTemplate}" />
<dfc:DfcGridViewColumn Header="IsCheap" Width="60" CellTemplate="{StaticResource IsCheap_DataTemplate}" />
<dfc:DfcGridViewColumn Header="NextTrade" Width="80" CellTemplate="{StaticResource NextTrade_DataTemplate}" />
</dfc:DfcGridView>
</ListView.View>
</dfc:DfcListView>
<Button Content="Add Row" HorizontalAlignment="Left" Margin="5,5,5,5" Click="AddRow_Click"/>
<Button Content="Update Row" HorizontalAlignment="Left" Margin="5,5,5,5" Click="UpdateRow_Click"/>
</StackPanel>
</Grid>
</Window>
Everything works fine until I include the StringFormat=ThisStringFormat, which mucks it up. But I somehow need to connect the StringFormat to the ThisStringFormat property expressed in the parent. I've experimented with changing StringFormat=ThisStringFormat to try to get to the templated parent, but to no avail.
Any ideas on how to solve this one?
The StringFormat property is just a regular property on BindingBase and regular properties cannot be binding targets only dependency properties can. So the answer is: You cannot not do it that way.
Some possible approaches:
Subclass TextBox and add a string format dependency property to which you can bind providing the required functionality
Augment your view model (if you have one) with a FormattedValue property (probably a bit ugly)
Use a MultiBinding for the Text property. One binding goes to Value and one to the ThisStringFormat of the templated parent. Then write a converter implementing IMultiValueConverter to return the formatted value.

WPF Tooltip Binding

I am only two weeks into WPF so this is probably a trivial question. I have a collection "CellList" which has a few properties I would like to bind to a ToolTip so when I hover over a label information from the current instance of CellList is displayed. How do I do that? I understand simple binding and this maybe simple binding too but I can't wrap my head around it. Below is my XAML for the label. Could someone explain to me how I can accomplish this.
<HierarchicalDataTemplate>
<ListBox ItemsSource="{Binding CellList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content=" " Height="20" Width="15" Background="{Binding Path=ExptNameBkg, Converter={StaticResource ExptNameToBrushConverter}}" BorderBrush="Black" BorderThickness="1" >
</Label>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HierarchicalDataTemplate>
Thanks.
The tricky thing about ToolTips is that a ToolTip is an object you associate with a control, and not part of the control's visual tree. So you can't populate it the way you'd populate things in the visual tree, e.g.:
<TextBox.ToolTip>
<StackPanel>
...put bound controls here
</StackPanel>
</TextBox.ToolTip>
Instead, what you have to do is create a specific instance of a ToolTip, and assign it a style that sets its DataContext (very important; that's how you can bind to the properties of the data source of its "placement target," i.e. the control that's displaying the tooltip) and its Template. Then put the visual tree of the ToolTip, including bindings, into the template. Finally, reference the ToolTip in your control.
So, here's a TextBox whose Binding does validation:
<TextBox ToolTip="{StaticResource ErrorToolTip}">
<TextBox.Text>
<Binding Source="SourceProperty">
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
It uses this ToolTip:
<ToolTip x:Key="ErrorToolTip" Style="{StaticResource ErrorToolTipStyle}"/>
And the ToolTip uses this style, which gets its content from the ValidationError property of the TextBox's binding source:
<Style x:Key="ErrorToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="DataContext" Value="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border
Name="Border"
BorderThickness="1"
BorderBrush="LightGray">
<StackPanel Orientation="Vertical">
<Label Background="Firebrick" Foreground="White" FontWeight="Bold" Margin="4">Validation error</Label>
<TextBlock Margin="10" Text="{Binding ValidationError}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
<Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm not certain of this, but I think that the only part of the above that actually has to be set in the style is the DataTrigger setting the DataContext; I think most everything else could just be explicitly set in the ToolTip's visual tree. But I'm probably not thinking of something important.
<Label Content={Binding Path=Id} ToolTip={Binding Path=Name}/>
just try this
Here's a kaxaml-ready example that includes a tooltip that is a little more elaborate than just text:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<XmlDataProvider x:Key="CharacterData">
<x:XData>
<Data xmlns="">
<Character First="Bart" Last="Simpson" Background="LightGreen" />
<Character First="Homer" Last="Simpson" Background="LightBlue" />
<Character First="Lisa" Last="Simpson" Background="Pink" />
<Character First="Maggie" Last="Simpson" Background="Yellow" />
<Character First="Marge" Last="Simpson" Background="PapayaWhip" />
</Data>
</x:XData>
</XmlDataProvider>
<ToolTip x:Key="ElaborateToolTip">
<Grid Margin="5">
<Rectangle RadiusX="6" RadiusY="6" Fill="{Binding XPath=#Background}" />
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="{Binding XPath=#First}" Margin="0,0,6,0" />
<TextBlock Text="{Binding XPath=#Last}" />
</StackPanel>
</Grid>
</ToolTip>
</Page.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource CharacterData}, XPath=Data/Character}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ToolTip" Value="{StaticResource ElaborateToolTip}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=#First}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>

Resources