WPF ContentControl ErrorTemplate - wpf

I have a content control that has 2 data templates as follows;
<ContentControl Content="{Binding ContentViewModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:TypeA}">
<vs:TypeAView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:TypeB}">
<vs:TypeBView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
My problem is that both TypeA view and TypeB view have a textbox that is bound to a Name property. On my containing control, when an item is selected from a treeview the ContentViewModel property is set.
The data displays and can be edited as I want. However I have a problem when my TypeB view's name field is made invalid (I'm using EntLib 5 validation and have implemented IDataErrorInfo - so my binding has ValidatesOnDataErrors=True). Whilst the error template for the control is displayed as expected, when I then click on to TypeA in the treeview the error message is still displayed even though TypeA's name textbox is valid.
It's as if the binding is getting mixed up which is which. Strange thing is that it only happens one way, i.e. going from an invalid TypeB name to the TypeA view. Doesn't seem to happen when going from an invalid TypeA view.
Can anyone help indicate what I've done wrong?
This is the error template I'm using for the textbox;
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border DockPanel.Dock="Left" Margin="0,0,2,0" Width="14" Height="14" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors), Converter={StaticResource ErrorContentConverter}}">
<Border.Background>
<RadialGradientBrush GradientOrigin="0.2,0.2" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
<RadialGradientBrush.GradientStops>
<GradientStop Color="Pink" Offset="0" />
<GradientStop Color="Red" Offset="1" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Border.Background>
<TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" />
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center">
<Border BorderBrush="Red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>

Related

WPF Button doesn't execute Command

I have a ListViewItem which has an Eventhandler attatched and inside the ControlTemplate of the ListViewItem is a Button which does something different. But if I click the Button, the Behaviour is like I clicked on the ListViewItem.
AppointmentOverview.xaml:
<Window.Resources>
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource NormalListViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style>
</Window.Resources>
Styles.xaml(My ResourceDictionary):
<!--Style für die normalen ListViewItems-->
<Style x:Key="NormalListViewItem" TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border BorderBrush="#5076A7" BorderThickness="1">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFFFFF" Offset="0.0"/>
<GradientStop Color="#FFFEB603" Offset="1.0"/>
</LinearGradientBrush>
</Border.Background>
<StackPanel TextElement.FontFamily="Segoe UI" TextElement.FontSize="12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="15"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="Betreff" Padding="3,0,0,0" Text="{Binding Betreff}" TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="0"/>
<Button Grid.Column="1" Grid.Row="0" Style="{StaticResource ListViewItemButton}"/>
AppointmentOverview.xaml.cs:
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var item = sender as ListViewItem;
if (item != null)
{
AppointmentOverviewViewModel apvm = this.DataContext as AppointmentOverviewViewModel;
apvm.editAppointment(item);
}
}
It worked when I had the complete ListViewItem Style in the Window.Resources of Appointmentoverview.xaml. But I didn't like that because the would kind of beat the purpose of Styles.xaml. Also I didn't have a Style for the Button, just did all the Styling inside the Button. But this was very Basic and now I need more complex Styling so I wanted to create a separate Style.
<Button FontSize="7" Content="X" Grid.Column="1" Grid.Row="0"
Command="{Binding DataContext.DeleteButtonCommand, RelativeSource={
RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding ItemId}"/>
Update:
If I observe my EventHandler this is also triggered if the Button is pressed. It just says the source is a Button but the command is not executed.
Styles.xaml.cs
void ListViewItem_MouseLeftDown(object sender, MouseButtonEventArgs e)
{
DependencyObject current = sender as DependencyObject;
while (current != null && current.GetType() != typeof(ListViewItem))
{
current = VisualTreeHelper.GetParent(current);
}
var item = current as ListViewItem;
if (item != null)
{
Window parent = Window.GetWindow(current);
AppointmentOverviewViewModel apovm = parent.DataContext as AppointmentOverviewViewModel;
apovm.editAppointment(item);
}
}
Styles.xaml
<!--DataTemplate für die normalen ListViewItems-->
<DataTemplate DataType="{x:Type local:SCSMAppointment}">
<Border BorderBrush="#5076A7" BorderThickness="1" PreviewMouseLeftButtonDown="ListViewItem_MouseLeftDown">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFFFFF" Offset="0.0"/>
<GradientStop Color="#FFFEB603" Offset="1.0"/>
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<Button FontSize="7" Content="X" DockPanel.Dock="Right" Width="15"
Command="{Binding DataContext.DeleteButtonCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding ItemId}"/>
<TextBlock Name="Betreff" Padding="3,0,0,0" Text="{Binding Betreff}" TextTrimming="CharacterEllipsis" />
</DockPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<TextBlock Padding="3,0,0,0" Text="{Binding Kunde}"/>
<TextBlock Padding="3,0,0,0" Text="|"/>
<TextBlock Padding="3,0,0,0" Text="{Binding IncidentId}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<TextBlock FontWeight="Bold" Padding="3,0,0,0" Text="{Binding Ort}"/>
<TextBlock Padding="3,0,0,0" Text="("/>
<TextBlock Text="{Binding Alternative}"/>
<TextBlock Text=")"/>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
It is apparent that your XAML is not correct. A ControlTemplate is primarily used to Specify the visual structure and behavioral aspects of a Control that can be shared across multiple instances of the control. In plain English, that means that they are used to change the default look of a Control. If that is not what you are doing, then you should not be using them.
On the other hand, DataTemplates Describe the visual structure of a data object, so you should be declaring DataTemplates to define what your data looks like instead of using ControlTemplates. Therefore, I suggest that you read the Data Binding Overview page on MSDN, which will give you a much better understanding, before you continue to work with WPF.
When you have updated your project, your problem will probably fix itself, but if it doesn't please return here to edit your question with your new XAML.

how to show selected text in combobox using custom template

I'm new in WPF, implementing application to show 2 combobox with different formated text.
I have created custom controltemplate for combobox
<ControlTemplate x:Key="GridGenreComboboxTemplate" TargetType="{x:Type ComboBox}">
<ControlTemplate.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent"/>
</ControlTemplate.Resources>
<StackPanel>
<ToggleButton
IsTabStop="False" x:Name="DropDownToggle"
HorizontalContentAlignment="Left"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter Content="{TemplateBinding SelectedItem}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="10,4"
VerticalAlignment="Center"
HorizontalAlignment="Left">
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{Binding Path=Foreground,RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}"/>
</Style>
</ContentPresenter.Resources>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Text ="{Binding}"></TextBlock>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</ToggleButton>
<!-- Popup for dropdown when combobox is clicked and open -->
<Popup x:Name="PART_Popup" AllowsTransparency="True"
Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Bottom" IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
<Grid MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="Splitter" BorderThickness="0,3,0,0">
<Border.BorderBrush>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color R="58" G="64" B="70" A="255"/>
</SolidColorBrush.Color>
</SolidColorBrush>
</Border.BorderBrush>
</Border>
<Grid Margin="0,3,0,0">
<Border CornerRadius="0,0,2,2" BorderThickness="1,0,1,1" x:Name="DropDownBorder"
Background="Green">
<Border.BorderBrush>
<SolidColorBrush Opacity="0.9">
<SolidColorBrush.Color>
<Color R="96" G="96" B="97" A="255"/>
</SolidColorBrush.Color>
</SolidColorBrush>
</Border.BorderBrush>
</Border>
<ScrollViewer CanContentScroll="true" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" x:Name="Content"
KeyboardNavigation.DirectionalNavigation="Continue" HorizontalAlignment="Stretch"/>
</ScrollViewer>
</Grid>
</Grid>
</Popup>
</StackPanel>
</ControlTemplate>
in one combobox want to show formated text i.e. 1000 x 900, 200 x 300,.. and in another want to show
text like 1000 900 topology, 200 300 topology
I have formated combobox item and it shows correct value but selected value doesn't show on combobox.
how to do this using single combobox item template?
<ComboBox Grid.Row="0" ItemsSource="{Binding PossibleTopologysNew}"
SelectedItem="{Binding SelectedTopologyNew}"
Template="{StaticResource GridGenreComboboxTemplate}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="10">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} x {1}">
<Binding Path="LeftNumber"/>
<Binding Path="RightNumber"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox Grid.Row="0" ItemsSource="{Binding PossibleTopologysNew}"
SelectedItem="{Binding SelectedTopologyNew}"
Template="{StaticResource GridGenreComboboxTemplate}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="10">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} topology">
<Binding Path="LeftNumber"/>
<Binding Path="RightNumber"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Your fix is simple... just don't declare a new ControlTemplate for the ComboBox - use the default one. If you really need to provide your own ControlTemplate, then just define one that contains the TextBox used to display the selected value. If you are new to WPF, then I very much doubt that you actually need to define your own ControlTemplate.
If however, you do need to declare your own ControlTemplate, then you should start with the default one (which you can find in the ComboBox Styles and Templates page on MSDN) and slowly and carefully remove the bits that you don't need and add the new bits that you do need. However, when declaring a ControlTemplate, you have to replace like with like. For example, look at the ContentPresenter from the default ControlTemplate:
<ContentPresenter x:Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Stretch"
HorizontalAlignment="Left">
Now look at yours:
<ContentPresenter
Content="{TemplateBinding SelectedItem}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="10,4"
VerticalAlignment="Center"
HorizontalAlignment="Left">
To start with, you are attempting to data bind the ContentPresenter.Content property to a different property from the original ControlTemplate. So if I were you, I'd get rid of you non-working ControlTemplate and replace it with the original one. Ensure that it displays correctly before starting to change it and test it regularly as you continue to change it.

ListViewItem custom template: ContentPresenter stays empty

I have the following ListView in my code. views:GameCard is a custom UserControl and {Binding} is a valid DataContext object with three items. Without the custom ItemContainerStyle everything works perfectly — the list shows three GameCards with correct info, etc. As soon as I add the ItemContainerStyle part, I get nothing but three "ABCD"s; so the data is still loaded correctly, but my UserControl is no longer displayed (I only added the "ABCD" to check if the data was there, as otherwise I got nothing but empty box).
Every piece of info I could find online seems to indicate that just putting a ContentPresenter element in the template should work, but it doesn't seem to in this case. What am I missing?
<ListView Grid.Row="1" ItemsSource="{Binding}" BorderThickness="0,0,1,0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF614B4B" Offset="0"/>
<GradientStop Color="#FFDA7070" Offset="1"/>
</LinearGradientBrush>
</ListView.Background>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<views:GameCard />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="ABCD" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
You need to set the TargetType of your ControlTemplate. And in order to make your ItemTemplate work, you'd also need to bind the Content and ContentTemplate properties.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid>
....
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
... />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
This may not be the case with you but so far I haven't had to modify the ItemContainerStyle yet, just the ListView.View. Since you're putting a Grid in your template style I'd assume you're looking for a GridView and this is how you do that:
<ListView.View>
<GridView>
<GridViewColumn Width="120">
<GridViewColumnHeader Height="14" >
<TextBlock Text="Type" FontSize="9"/>
</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, FallbackValue=MISSING}" />
<!-- or content presenter with bindings here -->
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
...
your style and everything is fine .All what required is to Assign or bind the Content property to your ContentPresenter. I hope this will help.

listview itemtemplate with an image

I am trying to create a ListViewItem template which looks like this, but i'm not making much headway.
Here is the style I have created so far:
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Border HorizontalAlignment="Stretch" Margin="1.5" CornerRadius="5" BorderThickness="1,1,1,1" BorderBrush="#FF997137">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF4B4B4B" Offset="0" />
<GradientStop Color="#FF8F8F8F" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<StackPanel Orientation="Horizontal" >
<Image HorizontalAlignment="Left" Width="32" Source="/Images/stop.png" Stretch="Fill" Height="32" />
<TextBlock Foreground="#FFECAD25" TextWrapping="Wrap" Width="150" >
This is a user control. The animation uses the attached BalloonShowing event.
</TextBlock>
<StackPanel Orientation="Vertical" >
<Image HorizontalAlignment="Right" Margin="0,10,5,0" VerticalAlignment="Top" Width="16" Height="16" Source="/Images/Close.png" Stretch="Fill"
Opacity="0.4" ToolTip="Delete" x:Name="Delete" />
<Image HorizontalAlignment="Right" Margin="0,5,5,0" VerticalAlignment="Top" Width="16" Height="16" Source="/Images/Close.png" Stretch="Fill"
Opacity="0.4" ToolTip="Edit" x:Name="Edit" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Is it possible to extend the text below the image/icon?
I don't believe there is any out-of-the box way to do this with a `TextBlock'.
However, if you are able to use the FlowDocument control, here are some options: answer 1, answer 2.
As far I know, no. Not atleast with simple Image and TextBlock.
FlowDocument seems to be good solution though,
check out this link for further information:
http://dotnetslackers.com/articles/wpf/WPFFlowDocumentsAndImages.aspx

Customize silverlight combobox component

This is (should be) a simple question.
I'd like to create a component like the Facebook notification button (so if you click it a drop down menu appears, and there is the "badge" with the number of unread notification).
I thought to customize the default combo box component (it has the popup and the toggle button), by removing the textfield and the arrow inside the toggle button, and by adding the toggle button inside a canvas so I can absolutely position the badge.
So.. I want to "export" some basic behavior, and the possibility to further stylish the component (like setting a template for the toggle button, for the badge and for each item in the list).
I can't find how can I achieve this.. make a "first" level of style so that people who use my component don't know it is a combo box, but instead they can set my properties (like "ButtonContent", "NotificationItem" and "Badge")…
Thank you.
Francesco
If you don't mind paying for 3rd party components there is always RadControls for Silverlight from Telerik. The suite contains the RadDropDownButton control, which I think should do exactly what you need.
I decided not to style the combo box, but to create a new component (strongly inspired by the combo box)
<UserControl x:Class="silverlight.Components.Notification.View.NotificationSummary"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:conv="clr-namespace:silverlight.ViewModel.Converters"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100">
<StackPanel x:Name="LayoutRoot">
<StackPanel.Resources>
<conv:NumberToVisibilityConverter x:Key="HasUnreadEventsConverter" />
</StackPanel.Resources>
<ToggleButton x:Name="eventButton" Click="notificationButtonClicked">
<ToggleButton.Content>
<StackPanel Orientation="Horizontal">
<Border Padding="5 3" VerticalAlignment="Center" HorizontalAlignment="Left">
<ContentPresenter x:Name="buttonContent" />
</Border>
<Border x:Name="badge" Padding="5 2" CornerRadius="5" Margin="0 0 5 0"
HorizontalAlignment="Right" VerticalAlignment="Center"
BorderThickness="1"
Visibility="{Binding numberOfUnreadEvents, Converter={StaticResource HasUnreadEventsConverter}}">
<Border.BorderBrush>
<SolidColorBrush Color="Black" />
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush Color="Red"/>
</Border.Background>
<TextBlock x:Name="badgeText" Text="{Binding numberOfUnreadEvents}"/>
</Border>
</StackPanel>
</ToggleButton.Content>
</ToggleButton>
<Popup IsOpen="{Binding ElementName=eventButton, Path=IsChecked}" x:Name="notificationPopup">
<Border x:Name="popupBorder" Background="White" CornerRadius="0 0 5 5"
Padding="5">
<Border.Effect>
<DropShadowEffect BlurRadius="5" Direction="315" ShadowDepth="5" Color="Black" />
</Border.Effect>
<ListBox x:Name="eventsList" ItemsSource="{Binding events}"
IsHitTestVisible="False">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter x:Name="itemTemplate" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Popup>
</StackPanel>
</UserControl>

Resources