WPF IDataErrorInfo issues - wpf

I've used WPF and IDataErrorInfo in the past apps to display errors to the user via a controltemplate by putting an image in the adorner and adding a tooltip to the image like this;
<Style x:Key="textStyle" TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border BorderBrush="Orange"
BorderThickness="2"
CornerRadius="4"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect BlurRadius="10"
ShadowDepth="0"
Color="Orange" />
</Border.Effect>
<DockPanel>
<Image Width="16"
Height="16"
Margin="-20,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality"
Source="{StaticResource imgError}"
ToolTip="{Binding ElementName=adornedElement,
Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"
ToolTipService.ShowDuration="30000" />
<AdornedElementPlaceholder Name="adornedElement" />
</DockPanel>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
With the appropriate implementation of IDataErrorInfo in the ViewModel and setting Textbox in the view accordingly the image and tooltip are shown;
<TextBox Name="txt"
Grid.Column="0"
Height="40"
Background="Aqua"
Style="{StaticResource textStyle}"
Text="{Binding Path=Text,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" />
<TextBlock Grid.Column="1"
Height="40"
Background="AliceBlue"
Text="{Binding ElementName=txt,
Path=(Validation.Errors).CurrentItem.ErrorContent}" />
The above code displays correctly in my previous apps and shows the error in the image tooltip as confirmed by the Textblock.
However, in my current app which is built using Prism I can't get the Image to display. The TextBlock updates correctly and I can set the error to the TextBox tooltip via a style trigger without any issue. The problem is I can't seem to get the image (or anything else) to display in the Adorner. The Image is not shown and border is not changed.
The difference between previous apps and this is that the view is in a Region in a ContentControl and I've used dependency injection to inject the viewmodel into the view constructor and set the DataContext.
I can't figure out why this doesn't work when it did previously. I think I may need to include an AdornerDecorator somewhere but I'm perplexed as to where having tried it in a few places without success. Any ideas how I can ensure the Adorner is shown?

Used an AdornerDecorator to wrap the element containing the texbox and all works fine.

Related

WPF Button from Controltemplate isn't visible

I want to instantiate two Controls (an Expander and a Button) from two ControlTemplates. They are docked in a Dockpanel (right and left). The Expander is visible and it works fine, but the Button isn't visible.
The ControlTemplate of the Button in App.xaml:
...
<ControlTemplate x:Key="OpenFileButton" TargetType="{x:Type Button}">
<Image Name="OpenFileButton" Source="F:\AudioNodeGUI_XAML\images\filebutton.jpg">
</Image>
</ControlTemplate>
...
And the instantiation in a usercontrol:
<Grid>
<Image Source="F:\AudioNodeGUI_XAML\images\FileInputNode.jpg"/>
<DockPanel Name="dock" Width="151" Height="20" Margin="27,53,122,139">
<Expander Name="expander" Template="{StaticResource FileExpander}" Height="20" Width="41" PreviewMouseLeftButtonUp="expand" DockPanel.Dock="Left">
<ListView Name="usedFiles" Background="Black" BorderBrush="Transparent" BorderThickness="0" Width="140" Height="120" Opacity="0.5">
</ListView>
</Expander>
<Button Name="OpenFileButton" Template="{StaticResource OpenFileButton}" DockPanel.Dock="Right" />
</DockPanel>
</Grid>
But the Button isn't visible, neither in the Designer (just the outline) nor in execution. What am I doing wrong?
I suspect that your issue is just incorrect path to the image file. Unfortunately you won't have any tip about this kind of error neither in designer nor in output window. However if you have ReSharper it should highlight the path to the file if it doesn't exist

How To Make A WPF UserControl Act As A Container

I'm trying to create a Toolbar control that can group selected buttons with a border and a label. If there is already a built-in control that will do this then I could use that instead of building a UserControl.
If not, then what I'm wanting to build is a UserControl that would allow me to enter one-to-many of my ImageButton UserControls and set a GroupLabel text like below. Can this be done in WPF?
<User_Controls:ToolbarGroup GroupLabel="Entity">
<User_Controls:ImageButton ButtonText="Entity Setup"/>
<User_Controls:ImageButton ButtonText="New Entity"/>
</User_Controls:ToolbarGroup>
PS: I would post an image but this quirky forum won't allow me to post an image.
If i have got you correctly then I think you can achieve this way also, and on mouse eneter and leave event you can do the button click job.
for setting text you can use a grid and a label inside it to set the text, and Image buttons below it.
<UserControl x:Class="ABC.View.Oats"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Image Source="{Binding Image}" Stretch="Fill"/>
</Grid>
</UserControl>
I think what you're looking for is a GroupBox, it has a header property where you can set the label.
Something like this:
<GroupBox Width="300" Height="100">
<GroupBox.Header>
<Label>Text</Label>
</GroupBox.Header>
<StackPanel>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</StackPanel>
</GroupBox>
I would also recommend using the groupbox, it seems to be doing exactly what you want it to do and it looks neat. Here's some examples on how to use them: http://www.dotnetperls.com/groupbox-wpf
On the other hand, if you believe the groupbox is not sufficient, you could create a control that inherits from the groupbox and you could extend it and add whatever you need to it. It would look like this:
public class customGroupBox: GroupBox{
....Add whatever you need here
}
Thanks for the replies. I tried the GroupBox and it's not the layout we want because we want the label underneath the buttons and centered. I never could find a way to add a collection to the UserControl. Maybe I didn't ask the question right by calling it a container. The code below will work, but it's not elegant. I wanted something that would wrap the layout in a UserControl and allow me to add a variable number of buttons to each toolbar group.
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 1"/>
<User_Controls:ImageButton ButtonText="New 2"/>
<User_Controls:ImageButton ButtonText="New 3"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 1"/>
</StackPanel>
</Border>
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 4"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 2"/>
</StackPanel>
</Border>
</StackPanel>
One way to accomplish this is with a custom styled ItemsControl.
You can then reuse it and just bind it to different data.
Please forgive me, this is hand-typed...
In your resources...
<Style x:Key="ToolbarGroupItemsControlStyle" TargetType="ItemsControl">
...
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Grid>
... XAML to form your group with a binding to the
... group name
<ItemsPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="ToolbarGroupItemTemplate">
<Grid>
... XAML and binding for each toolbar group item ...
</Grid>
</DataTemplate>
In your XAML...
<ItemsControl
Style="{DynamicResource ToolbarGroupItemsControlStyle}"
ItemsSource="{Binding ToolbarGroupItems}"
ItemTemplate="{DynamicResource ToolbarGroupItemTemplate"/>
If your resources above are at the application level, then you can place the ItemsControl above on any Window/UserControl you want.
Your ItemsSource will need to be a collection of a custom type you create that has bindings for the button text, etc.
I hope this is helpful.

Presenting an ItemsControl

simple question!
I want to present an itemscontrol inside of an expander and grid which contains a textbox. I want to do this multiple times so I wrapped it in a ControlTemplate.
<ControlTemplate x:Key="ArrayPresenter">
<Expander Template="{StaticResource ArrayTemplate}">
<Grid>
<ContentPresenter/>
<TextBlock FontWeight="Bold" Text="Empty" Margin="3" HorizontalAlignment="Center" Foreground="#66C9C9C9" FontSize="15" Visibility="{quickConverter:Binding '$P.Count == 0 ? Visibility.Visible : Visibility.Collapsed', P={Binding Array}}" />
</Grid>
</Expander>
</ControlTemplate>
This is what I want to present. Unfortunately whenever an item is added to the itemscontrol, nothing happens and it doens't display the new items!
<ContentControl Template="{StaticResource ArrayPresenter}">
<ItemsControl Style="{StaticResource ArrayItemsStyle}" Margin="5" ItemTemplate="{StaticResource StructureFieldTemplate}"/>
</ContentControl>
As mentioned in the comment you need to target type of your ControlTemplate
<ControlTemplate ... TargetType="{x:Type ContentControl}">
Without that ControlTemplate targets System.Windows.Controls.Control type and that does not have Content to present so ContentPresenter does not know what to show.

Control to use for Reusable container for content/content template?

I am creating a container whose style will be used across the application. It essentially is a 'pop up' but won't spawn in a new window. The general structure of my app is one NavigationWindow and many pages. So I get started with the following Template, defined in my Resource Dictionary:
<ControlTemplate x:Key="RainbowModalTemplate" TargetType="{x:Type Control}">
<Canvas Height="540" Canvas.Left="492" Canvas.Top="296" Width="945">
<Border x:Name="Modal" Height="540" Width="945" Background="#ec2016" BorderBrush="White" BorderThickness="2" CornerRadius="15" Style="{DynamicResource RainbowModalBox}">
<Border.Clip>
<RectangleGeometry RadiusX="15" RadiusY="15" Rect="0,0,945,540"/>
</Border.Clip>
<Image Source="Resources/RainbowModal/rainbow.png" Height="247" Width="947" Margin="0,0,0,0" VerticalAlignment="Bottom" d:LayoutOverrides="Height" Stretch="UniformToFill" Canvas.Left="-2" Canvas.Top="293" ClipToBounds="True" />
</Border>
</Canvas>
</ControlTemplate>
So when I want to 'consume' this, I want to be able to implement this control but provide my own content inside, (buttons, text, etc). However because I am new to WPF I am unsure what control or controls to use, and what structure to lay this out as. Below is sample 'consumer' of the object. Someone will click a button in the application and that will set this objects' visibility to be Visible :
<Control x:Name="RequestMoreInfoModal" Template="{DynamicResource RainbowModalTemplate}" Canvas.Left="494" Canvas.Top="250" Visibility="Collapsed"></Control>
I know this probably isn't the most kosher way to do this, so I am open to suggestion. My specific concerns:
I know "Control" isn't the right type. But I don't know what is appropriate and it appears Canvas and other controls do not allow Templating. What control should I use?
how do I implement this Template and also allow the consumer to define their own content within the Template?
What I eneded up doing is using a ControlTemplate and ContentPresenter.
Here is the definition of the reusable content in my ResourceDictionary:
<ControlTemplate x:Key="RainbowModal" TargetType="ContentControl">
<Canvas>
<Border x:Name="Modal" Height="540" Width="945" Background="#ec2016" BorderBrush="White" CornerRadius="15" BorderThickness="2" Style="{DynamicResource RainbowModalBox}">
<Border.Clip>
<RectangleGeometry
RadiusX="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource AncestorType={x:Type Border}}}"
RadiusY="{Binding RadiusX, RelativeSource={RelativeSource Self}}"
Rect="0,0,945,540"/>
</Border.Clip>
<Canvas>
<Image Source="Resources/RainbowModal/rainbow.png" Height="247" Width="947" Margin="0,0,0,0" VerticalAlignment="Bottom" Stretch="UniformToFill" Canvas.Left="-2" Canvas.Top="293" ClipToBounds="True" />
<ContentPresenter/>
</Canvas>
</Border>
</Canvas>
</ControlTemplate>
And here is the 'consumption' of that content.
<ContentControl x:Name="RequestMoreInfoModal" Canvas.Left="489" Canvas.Top="122" Template="{StaticResource RainbowModal}" Visibility="Collapsed">
<Canvas>
<TextBlock FontSize="78" Foreground="White" Width="903" Canvas.Top="28" Canvas.Left="20" Height="298" Text="Scan your card to receive an email with more information." TextWrapping="Wrap" FontFamily="Serif72 Beta" TextAlignment="Center" />
<Button Width="250" Height="76" Content="CLOSE" Margin="350,350" Style="{DynamicResource PurpleInfoButton}" FontSize="28" Click="Button_Click_1" ></Button>
</Canvas>
</ContentControl>

WPF Changing text in a controltemplate at run time

I am making a template control so that I can have a button with an image that changes when you click it. I also am trying to get text on top of the button that can change at run time. I have the button images and everything working but I can't seem to get that label at runtime so I can change the text. Here is the code in the xaml. I am missing the code behind
<UserControl.Resources>
<ControlTemplate TargetType="{x:Type Button}" x:Key="ActionButton">
<Grid>
<Label Panel.ZIndex="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Arial" Name="lblText" Foreground="#5E4421" FontWeight="Bold" FontSize="14">Test</Label>
<Image Name="Normal" Source="/AssaultWare.Controls;component/Replayer/Images/button_off.png"/>
<Image Name="Pressed" Source="/AssaultWare.Controls;component/Replayer/Images/button_on.png"/>
<Image Name="Disabled" Source="/AssaultWare.Controls;component/Replayer/Images/button_off.png" Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Resources>
<Button Canvas.Left="471" Canvas.Top="465" Template="{StaticResource ActionButton}" Name="btnRight"/>
Difficult to decipher your question, but I think you just need to change the Label to a ContentControl and bind its Content property to the Button's Content property:
<ContentControl Content="{TemplateBinding Content}" .../>

Resources