How to use Validation template without the Validation mechanism? - wpf

I'm using a control template to show validation errors on each of my controls using the built-in WPF's validation mechanism, and everything works fine. The controlTemplate looks like this:
<ControlTemplate x:Key="MyErrorTemplate" TargetType="{x:Type Control}">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="3">
<AdornedElementPlaceholder Name="MyAdorner" />
</Border>
<Image Name="imgError"
Source="/MyAssembly;component/Images/ValidationIcon.png"
ToolTip="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
I have read that the validation mechanism wraps the validated control up with the control template (the default one or a custom one like above) whenever the control gets an error.
"When the WPF validation system detects an invalid control it creates
and adorner that holds a control (...), inserts a control into it and sets that control
template to the content of the Validation.ErrorTemplate attached
property.
It positions the adorner above the original control so that the
AdornedElementPlaceholder is exactly above the control and that let us
easily place the control template content relative to the original
control" (see more)
How can I perform this same behavior for another functionality? I mean use "MyErrorTemplate" without the WPF's validation system, is it possible?

so if I understand you correctly you want to have the same validation adorning thing without WPF's validation, right?
The approach then is actually to rebuild the components of WPF's validation system:
create a Dependency Property MyCustomErrorTemplate to hook up your template to the control
create a Dependency Property HasCustomError to enable showing the error
within MyCustomErrorTemplate_Changed hook up to the HasCustomError_Changed to enable showing/hiding of your adorner
create/copy the TemplatedAdorner Class that is then showing your Template
I recommend you use .NET Reflector or ILSpy to look at the following code to get some understanding of what's going on. This isn't actually very complex or hard to understand:
in PresentationFramework.dll:
System.Windows.Controls.Validation (especially the private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show, bool tryAgain)
MS.Internal.Controls.TemplatedAdorner (sadly this is internal, so you either have to copy it or use some Reflection on it)

Why not? You can have similar attached properties MyValidation.Errors and HasErrors and fill them with your custom logic. And you can have trigger that replaces ControlTemplate with ErrorTemplate when HasError is true. I think this simple approach will do that you need although i am not quite sure that i exactly understand that you need.

Related

What's the difference betwen a UserControl and a ContentControl?

According to all of the documentation, when you're creating a non-lookless control, you're supposed to subclass UserControl. However, UserControl is a simple subclass of ContentControl but it doesn't appear to add anything to it, interface-wise. As such, you can take that designer-generated code and change the base class to ContentControl and it appears to still work exactly the same.
So what's the point of UserControl over ContentControl?
Update:
For those who keep answering Visual Studio treats them differently, I'd argue that isn't the case. Try it! Create a new UserControl in Visual Studio, then in the resulting XAML file, change the root tag to ContentControl. Then in the associated class file, change the base class to ContentControl or simply delete it as I have done here (see the note) and you'll see it appears to work exactly the same, including full WYSIWYG designer support.
Note: You can delete the base class from the code-behind because it's actually a partial class with the other 'part' of the class being created by the XAML designer via code-generation. As such, the base class will always be defined as the root element of the XAML file, so you can simply omit it in the code-behind as it's redundant.
Here's the updated XAML...
<ContentControl x:Class="Playground.ComboTest.InlineTextEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="Success" />
</ContentControl>
...and the associated class file...
namespace Playground.ComboTest {
public partial class InlineTextEditor {
public InlineTextEditor()
=> InitializeComponent();
}
}
UserControls are a good fit for aggregating existing controls when you don't need to provide the consumer a ControlTemplate. This means that UserControls are not lookless. Why not just use ContentControl as it can have coupled XAML like a UserControl and the implementation looks similar to UserControl? Well, there are several important technical differences you must know:
UserControls set themselves as the source to RoutedEvents raised by elements within them. This means that when an element outside the UserControl receives a bubbled event, the Source is the UserControl, not the thing you interacted within the UserControl. In the philosophical sense of what you often hear about UserControls, "It's for aggregating existing controls", this makes sense as you want the parent container element to think of your UserControl as a single unit. For example, your UserControl contains a button that the user clicks and the Grid that contains your UserControl instance receives the MouseLeftButtonUp event but the Button is not the Source of the event, your UserControl is.
UserControl sets Focusable and IsTabStop to false. You can see the philosophy demonstrating itself again here as we don't want a grouping of existing controls to be Focusable.
UserControl sets HorizontalAlignment and VerticalAlignment to Stretch. A ContentControl would automatically be set to Left and Top.
UserControl's own AutomationPeer implementation allows you to change VisualStates via VisualStateManager.GoToState(). ContentControl requires the VisualStateGroups to be at the top-level and you must call them with VisualStateManager.GoToElementState().
UserControl's own ControlTemplate wraps your content in a Border. This again makes sense when thinking of the philosophical use case for UserControl.
UserControl's own ControlTemplate provides more TemplateBindings than ContentControl. This is kind of a recapitulation of some above items but explains how they are possible. Recall that UserControl provides a Border so that relates to some of these free TemplateBindings you see below. This enables respect for BorderBrush, BorderThickness, Background and Padding properties on your control that would otherwise not work with just a ContentControl. For example, if you just derive your control from ContentControl and set the Background property on the root ContentControl element it will not work because the ControlTemplate of ContentControl has no TemplateBinding for Background. Of course you could set the Background property on the child content element that wraps your desired elements, like a Grid, but that isn't ideal IMO.
ContentControl's ControlTemplate
<ControlTemplate TargetType="ContentControl">
<ContentPresenter
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" />
</ControlTemplate>
UserControl's ControlTemplate
<ControlTemplate TargetType="UserControl">
<Border BorderBrush="{TemplateBinding Border.BorderBrush}"
BorderThickness="{TemplateBinding Border.BorderThickness}"
Background="{TemplateBinding Panel.Background}"
Padding="{TemplateBinding Control.Padding}"
SnapToDevicePixels="True">
<ContentPresenter
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
Content="{TemplateBinding ContentControl.Content}" />
</Border>
</ControlTemplate>
Basically, the UserControl class is there for convenience. It enables us to build little parts of the UI from already existing controls, whereas ContentControls are really for creating new controls, generally with a single purpose and/or functionality.
I read a book that had a good explanation of this and by good luck, someone has 'put a copy of it online'. From the linked book:
The UserControl class is a container class that acts as a “black box” container for a collection
of related controls. If you need a set of three controls to always appear together and
be allowed to easily talk to each other, then a likely candidate for making that happen is
the UserControl class.
Then relating to whether to create a CustomControl:
The following is a summary of the decision process:
Use the framework as much as possible. WPF provides a variety of extensible
controls, so make sure that the functionality you want doesn’t already exist in a
WPF control.
In many cases, the data structure you’re working with requires different visual representation.
Using ControlTemplates and DataTemplates can often get you the functionality
you need.
Look at ValueConverters to see whether they can help bridge the gap between the
stock functionality and what you need.
Finally, see whether you can’t extend existing behavior with attached properties.
Take a look for an in depth answer to your question:
WPF Control Development Unleashed
UPDATE >>>
#MarqueIV, to answer your question more directly: The UserControl class is provided to us for convenience. That's it. If you add a WPF CustomControl into your project, you will see that it has no XAML file. This means that you have to design you control markup in a file called Generic.xaml in the Themes folder. The UserControl class gives us a XAML file so that it is easier to create them... so it is more convenient... that's it. That's the reason.
One thing that is different from ContentControl is that UserControl overrides the OnCreateAutomationPeer method, you might look for that. Maybe it has some different UI-behaviors than the ContentControl.
This method creates an UserControlAutomationPeer-instance.
ContentControl
A ContentControl directly derives from Control class.
It hosts a single element which can be a container (eg Grid, Stackpanel, ...) hosting itself several elements (eg StackPanel with TextBlock and Image children).
Its appearance can be modified through a DataTemplate.
See MSDN Remarks section.
UserControl
A UserControl derives from ContentControl.
It does NOT support templates, thus no customization.
It does not catch focus automatically like a Window would.
Still in the MSDN Remarks section.
UserControl is a composite control. It has similar concept with UserControl in ASP.NET Webforms. This means it's a control that is composed from many controls. In WPF, creating user control has supports for designer in Visual Studio 2008 and above.
ContentControl is a control that is intended to have a single control as its content.
For more information:
http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.aspx
UserControl and ContentControl maybe the same implementation but the use case are not the same.
we need to answer two questions when to use UserControl or CustomControl?
and when to use ContentControl?.
so when to use a UserControl or CustomControl?
Whenever I want to have a reusable piece of UI
for example if I want to have a FileDialogBrowser meaning a button with a TextBlock next to it so whenever i press the button and a user chooses a file i will show the chosen file in the TextBlock.
same but not exactly goes for customControl however here we want to do something more sophisticated, anyway this is not the issue.
so when to use ContentControl?
this is a little tricky to say but let's say we want to have progressBar with a message
so we can inherit from BusyIndicator or Border, however if we use a ContentControl we have control which can Control the content inside it. we can have it wrapping around other xaml elements.
hope this helps

KeyboardNavigation.ControlTabNavigation Application Wide?

I have an issue I've been trying to deal with - the following:
KeyboardNavigation.ControlTabNavigation="None"
doesn't seem to work anyplace in my application despite my best efforts...I'm not entirely sure why but regardless of what I do, the CTRL+TAB functionality always works, and in my case the behavior is detrimental to how I'd like my tab controls to operate. Ideally, rather than placing the above tag in every container in my application (which I can't get to work anyway), I'd like to disable ControlTabNavigation across the entire application. Is there a way to do this without having to go container by container, and is there any obvious "gotchas" that normally keep the above from working properly?
Thank you!
Aj
I find that the KeyboardNavigation does not work as I would expect as it pertains to Ctrl-Tab and a TabControl. I put together a simple prototype and KeyboardNavigation.ControlTabNavigation="None" just does not seem to have the expected impact on the switching of Tabs using Ctrl-Tab, once I left-click a tab and the keyboard focus is within the TabControl.
However, using InputBindings with a Command can override the unwanted Ctrl-Tab default behavior. From there, I found that KeyboardNavigation.TabNavigation="Cycle", as well as the other the other options for TabNavigation seem to behave reasonably. Using The FocusManager and other techniques described in the resource links below should allow one to obtain desired keyboard navigation, albeit using somewhat counter-intuitive techniques.
The InputBindings do have to be set for each control that has the unwanted default behavior, although a more sophisticated solution might walk the visual tree to set the InputBindings for all controls of a certain type, for example. I found having the Command simply do nothing neutralizes the key sequence adequately. In my example, I display a dialog box for testing.
Note, below Command binding requires you target WPF 4.0; please see resources at end of post for resource on how to target WPF 3.5 or earlier
In XAML:
<TabControl
x:Name="tabControl1"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedTabItem}"
ItemsSource="{Binding TabItemViewModels}"
KeyboardNavigation.ControlTabNavigation="None"
KeyboardNavigation.TabNavigation="Continue">
<TabControl.InputBindings>
<KeyBinding Modifiers="Control"
Key="Tab"
Command="{Binding ShowDialogCommand}" />
</TabControl.InputBindings>
</TabControl>
Note, in above XAML, KeyboardNavigation.ControlTabNavigation="None" is of no effect and can be eliminated.
In backing DataContext, typically a ViewModel:
Declare your binding property:
public RelayCommand ShowDialogCommand
{
get;
private set;
}
Initialize the property; for example, can be in the constructor of the ViewModel (Note, RelayCommand is from MVVM-Light library.):
ShowDialogCommand = new RelayCommand(() =>
{
MessageBox.Show("Show dialog box command executed", "Show Dialog Box Command", MessageBoxButton.OK, MessageBoxImage.Information);
});
Resources:
Helpful StackOverflow post on KeyBindings
More detail on KeyBinding to a Command; describes special CommandReference technique needed if targeting WPF framewrok 3.5 or earlier
Microsoft's Focus Overview
I hadn't looked at this issue in a while, but since Bill asked it sparked a renewed interest. Rather than going control by control, I used an empty command as Bill suggested, but applied it to a TabControl template...as Bill pointed out, somewhat of a counter-intuitive solution, but it works (I also accounted for Ctrl+Shift+Tab which is just the opposite direction of Ctrl+Tab):
MyClass:
public static readonly RoutedCommand CancelTabChangeCommand = new RoutedCommand() { };
XAML:
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.InputBindings>
<KeyBinding Command="{x:Static local:myClass.CancelTabChangeCommand}" Key="Tab" Modifiers="Control" />
<KeyBinding Command="{x:Static star:Startup.CancelTabChangeCommand}" Key="Tab" Modifiers="Shift+Control"/>
</Grid.InputBindings>
I left off the rest of my class and XAML as it wasn't pertinent to the example, but I'm happy to provide more if anyone needs it. On a related note, I also found that create a control template for the TabItem and setting the IsTabStop property to false also keeps my users from tabbing across and changing tabs in that fashion as well...in case anyone was having this issue as I was.
Hope it helps!

Control Template that wraps another control in XAML

I want to create a custom control that extends a built-in control and then has a template that wraps that control with a container?
The C# class:
class ExtraBorderTextBox : TextBox {}
The Xaml:
<ControlTemplate>
<Border>
<TextBox/>
</Border>
</ControlTemplate>
That doesnt' work because the TextBox in the control template isn't my custom control, it is a second instance.
I need access to the properties and events on TextBox, having a different parent doens't make sense, I would have to replicate all of that in my class.
This is a simplified example; imagine Border being replaced with a ContentControl that has a 50 line control template for itself. I guess I want something like ContentPresenter (like I have in the ContentControl), but there isn't anything like a "ControlPresenter". Right? Am I missing something, or am I stuck with replicating my content control for the TextBox, or replicating the TextBox behaviour and presentation for my content control?
Thanks.
Update:
There is an answer here that does what I want, which is to copy the default template for System.Windows.Controls.TextBox. This will do what I want; I can insert my container into that. I was hoping that WPF provided a way that is more maintainable to do something like this, something like a adorner/decorator pattern.
Is there any way to make this better in some way? Would using something like Expression Blend make this so that I don't have to hand-edit the XAML pasted in from the webpage?
You could use the default control template as a base and modify it. The default control templates can be found here: http://msdn.microsoft.com/en-us/library/aa970773.aspx
If I understood you right, you want to inherit from TextBox, do some overriding, and use that new class in XAML.
If so:
1) declare the xmlns namespace at the top of your file:
<UserControl
...
xmlns:local="TheAssemblyWhereExtraBorderTextBoxResides"
...>
2) use your custom textbox:
<ControlTemplate>
<Border>
<local:ExtraBorderTextBox />
</Border>
</ControlTemplate>

How do you navigate a complex Visual Tree in order to re-bind an existing element?

In the above image, child is a ContentPresenter. Its Content is a ViewModel. However, its ContentTemplate is null.
In my XAML, I have a TabControl with the following structure:
<local:SuperTabControlEx DataContext="{Binding WorkSpaceListViewModel}"
x:Name="superTabControl1" CloseButtonVisibility="Visible" TabStyle="OneNote2007" ClipToBounds="False" ContentInnerBorderBrush="Red" FontSize="24" >
<local:SuperTabControlEx.ItemsSource>
<Binding Path="WorkSpaceViewModels" />
</local:SuperTabControlEx.ItemsSource>
<TabControl.Template>
<ControlTemplate
TargetType="TabControl">
<DockPanel>
<TabPanel
DockPanel.Dock="Top"
IsItemsHost="True" />
<Grid
DockPanel.Dock="Bottom"
x:Name="PART_ItemsHolder" />
</DockPanel>
<!-- no content presenter -->
</ControlTemplate>
</TabControl.Template>
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:WorkSpaceViewModel}">
....
WorkSpaceViewModels is an ObservableCollection of WorkSpaceViewModel. This code uses the code and technique from Keeping the WPF Tab Control from destroying its children.
The correct DataTemplate - shown above in the TabControl.Resource - appears to be rendering my ViewModel for two Tabs.
However, my basic question is, how is my view getting hooked up to my WorkSpaceViewModel, yet, the ContentTemplate on the ContentPresenter is null? My requirement is to access a visual component from the ViewModel because a setting for the view is becoming unbound from its property in the ViewModel upon certain user actions, and I need to rebind it.
The DataTemplate is "implicitly" defined. The ContentPresenter will first use it's ContentTemplate/Selector, if any is defined. If not, then it will search for a DataTemplate resource without an explicit x:Key and whose DataType matches the type of it's Content.
This is discussed here and here.
The View Model shouldn't really know about it's associated View. It sounds like there is something wrong with your Bindings, as in general you should not have to "rebind" them. Either way, an attached behavior would be a good way to accomplish that.
I think the full answer to this question entails DrWPF's full series ItemsControl: A to Z. However, I believe the gist lies in where the visual elements get stored when a DataTemplate is "inflated" to display the data item it has been linked to by the framework.
In the section Introduction to Control Templates of "ItemsControl: 'L' is for Lookless", DrWPF explains that "We’ve already learned that a DataTemplate is used to declare the visual representation of a data item that appears within an application’s logical tree. In ‘P’ is for Panel, we learned that an ItemsPanelTemplate is used to declare the items host used within an ItemsControl."
For my issue, I still have not successfully navigated the visual tree in order to get a reference to my splitter item. This is my best attempt so far:
// w1 is a Window
SuperTabControlEx stc = w1.FindName("superTabControl1") as SuperTabControlEx;
//SuperTabItem sti = (SuperTabItem)(stc.ItemContainerGenerator.ContainerFromItem(stc.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(stc);
//ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(sti);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
The above code is an attempt to implement the techniques shown on the msdn web site. However, when I apply it to my code, everything looks good, except myDataTemplate comes back null. As you can see, I attempted the same technique on SuperTabControlEx and SuperTabItem, derived from TabControl and TabItem, respectively. As described in my original post, and evident in the XAML snippet, the SuperTabControlEx also implements code from Keeping the WPF Tab Control from destroying its children.
At this point, perhaps more than anything else, I think this is an exercise in navigating the Visual Tree. I am going to modify the title of the question to reflect my new conceptions of the issue.

MVVM Command without A Button

I want to initiate a bound command, but I don't want to use a Button on my UserControl. In effect the UserControl is itself a Button. When it is clicked anywhere on its surface I want to initiate a bound command. Is there a way to give a UserControl a command?
In a side note: one command for one control and only a few certain out-of-the-box controls? This all seems a little clunky. I'm starting to think that MVVM is impractical. I can decouple my UI just fine with Interfaces and OOP. Anyway, I still have hope.
Also, I'm not willing to hack anything or use an expensive workaround. If I can't do this, I'm abandoning MVVM.
Take a look at the ICommandSource interface here: http://msdn.microsoft.com/en-us/library/system.windows.input.icommandsource.aspx. If you want a control to have a command, then your control should implement this interface. Examples of controls that implement this interface are ButtonBase and MenuItem. Hope this helps.
If your UserControl is essentially a Button, why are you writing your own UserControl instead of using the Button class?
To add more info, here's what you do:
Subclass Button, put any extra DependencyProperties that you need in there - it should be a very empty class (you could even have something like public class MyCoolButton : Button { }
Add a Style whose TargetType is MyCoolButton - don't name the style so it applies to all MyCoolButtons
Override the default Template of the style, then paste in your Xaml code. You might have to do some work here to handle the "Normal / Pushed / Disabled" states. If you're using v4.0, you can use VSM here.
I will agree with Paul Betts.
Quite often I create my own ListBoxItemContainerStyle using a button as the top container with nothing but a propertyless content presenter in it. This allows me to use the buttons functionality (like Command) without having the Windows chrome on it.
Putting it in the ListBoxItemContainerStyle also lets me make it so that when it is clicked it does not display the normal dotted border (FocusVisualStyle={x:Null}).
Are you using Visual Studio or Expression Blend to do your styling?
Additionally, some MVVM frameworks provide an interface for adding a command-ish ability to controls other than buttons. Caliburn has a pretty rich command pattern. I am not sure if it allows binding commands on non-button controls, however.
The OP asked for an example of how you could use a button control, but with the content properly filling the entire button. You can do this using the ContentAlignment properties:
<Button HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Button.Content>
<Grid IsHitTestVisible="False">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Row0" />
<TextBlock Grid.Row="1" Text="Row1" />
</Grid>
</Button.Content>
</Button>
This creates a button with two labels spaced using a Grid control. I mark the Grid to turn off HitTestVisible, as you have to decide which controls should interact like the button and which should interact like controls. For instance, you might have an embedded TextBox that you want to be clickable without clicking the button, in which case it should have HitTestVisible=True.
WPF supports layers and transparency :
Panel.ZIndex
You can create anything that supports commanding on a superior transparent layer, the size you want, to act as a button.

Resources