How to handle Validations on Custom Control - wpf

I recently wrote my first custom control, an autocomplete textbox. Its Controltemplate consists of something like this
<Grid >
<Border/>
<TextBlock x:Name="Label"/>
<TextBox x:Name="TextLabel"/>
</Grid>
The first Textblock is used as a Label, the second one shows the content. The TextLabel binds on an Object, let's call it Customer If the underlying search doesn't find a Customer object, I want to show the errortemplate. When defining the TextLabel like this
<TextBox x:Name="PART_Editor"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Validation.ErrorTemplate="{DynamicResource ValidationErrorTemplate}"
Style="{StaticResource TransparentTextBoxStyle}"
Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=TemplatedParent},
Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True,
ValidatesOnDataErrors=True,
UpdateSourceTrigger=PropertyChanged}" >
</TextBox>
the Validation is made and the error template of the textbox is shown. Unfortunately the Red Border is only around the inner TextBox and not around the whole custom control which looks just not good.
I was wondering how to achieve two things:
How can the ErrorTemplate of the CustomControl be triggered when one of the child-validations fail?
Do I have to specify all these NotifyOnValidationerror properties or is it possible to catch all errors on entity level and show the same ErrorTemplate
If you need additional Information, please just ask

Related

WPF TextBox in DataTemplate of ToggleButton does not show text if in toolbar flyout

If I put the Column where the toolbar is hosted to be very big (800) then all the text is visible:
but if I put a smaller column this happens:
But I cannot understand why:
<DataTemplate x:Key="IconFilterButton">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
Style="{StaticResource LargeIconStyle}"
Text="{Binding}" />
<TextBlock
Margin="6,0,0,0"
VerticalAlignment="Center"
DataContext="{Binding}"
Style="{StaticResource BodyTextStyle}"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton}, Path=Tag}" />
</StackPanel>
</DataTemplate>
and here the definition
<ToggleButton
x:Name="DFilter"
Click="Filtering_Click"
Content=""
ContentTemplate="{StaticResource IconFilterButton}"
Tag="1d"
/>
<ToggleButton
x:Name="WFilter"
Click="Filtering_Click"
Content=""
ContentTemplate="{StaticResource IconFilterButton}"
Tag="1w"
/>
Even worst if I click on the button once they are out:
and then the text is visible but is wrong as the TextBlock is not considered in the object size:
The WPF ToolBar control uses a custom panel for the overflow Popup. In many styles, the ToolBarOverFlowPanel has a property WrapWidth set to a static value like 200. This determines how many items can be displayed before it wraps to another row in the popup.
I've created custom styling for this control and have found that the ToolBarOverFlowPanel used internally is buggy. That's probably the source of your problem.
You can re-template the ToolBar and wire-up a different value for WrapWidth to try to fix the issue, but my guess is that you'll still run into layout problems.
Otherwise, you might consider making your own replacement control.

Getting a tooltip in a user control to show databound text and stay open

I have a user control that shows a TextBox along with a small help icon.
My goal is to have a ToolTip pop-up, show some databound text and stay open when the mouse hovers over the help icon.
So, to that end I have created a HelpText dependency property in the user control allowing me to bind a help text string to the user control.
So, my user control looks something like this
<UserControl Name="textField" ...>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ElementName=textField,Path=Text}"/>
<Image Source="{StaticResource Help.Icon}">
<Image.ToolTip>
<ToolTip Content="{Binding ElementName=textField,Path=HelpText}"/>
</Image.ToolTip>
</Image>
</StackPanel>
</UserControl>
This code does show the tooltip, except that it is empty! Also, the StaysOpen property does not make any difference as the tooltip shuts down after a few seconds.
Funny thing is that when I set the same binding directly on the Image control's ToolTip property the bound text is shown allright in the tooltip pop-up, however it still does not stay open:
<Image Source="{StaticResource Help.Icon}" ToolTip="{Binding ElementName=textField,Path=HelpText}">
So my to questions are:
How come the binding against the user control's HelpText dependency property does not work in the first code sample but does work in the second?
How do I make the ToolTip stay open or rather how do I make the ToolTip both stay open and show the databound text?
Thanks!
ToolTips are not part of the same VisualTree as the rest of your XAML, so the DataContext is not inherited the way you would expect it to be.
Writing ToolTip="{Binding SomeProperty}" will automatically set the ToolTip's DataContext to SomeProperty, however if you build a custom ToolTip you must do this yourself.
<ToolTip DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}" ... />
This will bind the ToolTip's DataContext to the DataContext of whatever object the ToolTip is on.
To accomplish what you're trying to do, your <ToolTip> would probably look like this, since PlacementTarget would be your Image:
<!-- Could also use something like Tag if DataContext is actually used -->
<Image DataContext="{Binding ElementName=textField, Path=HelpText}"
Source="{StaticResource Help.Icon}">
<Image.ToolTip>
<ToolTip Content="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}"/>
</Image.ToolTip>
</Image>
As for why it won't stay open, I'm not positive but it might be because the ToolTipService.ShowDuration property defaults to 5 seconds, and that probably overwrites the StaysOpen property.
You can try setting it to something higher, such as
<Image ToolTipService.ShowDuration="60000" ... />
Or you can try this workaround of using a Popup styled to look like a ToolTip instead. The code would probably look something like this:
<Popup PlacementTarget="{Binding ElementName=MyImage}"
IsOpen="{Binding IsMouseOver, ElementName=MyImage, Mode=OneWay}">
<TextBlock Text="{Binding ElementName=textField, Path=HelpText}" />
</Popup>

How do I access a windows control (checkbox) that is created dynamically in a WPF treeview?

I have a WPF Tree View with hierarchical data templates that loads objects and displays them fine. Within the children of the treeview, I am showing the "Name" of the object in the Tree View using a TextBlock, along with a Check Box next to it. Here is my code for reference:
<DockPanel Name="test1" Margin="10,10,0,10" VerticalAlignment="Stretch" Grid.Row="3" Grid.RowSpan="7" Grid.Column="0">
<DockPanel.Resources>
<local:CheckBoxCommand x:Key="cbc"></local:CheckBoxCommand>
<src:TreeViewFilter x:Key="MyList" />
<HierarchicalDataTemplate DataType="{x:Type src:TreeViewParent}" ItemsSource="{Binding Path=OrderAttributes}">
<TextBlock Text="{Binding Path=NameAndCount}" FontSize="24"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type src:OrderAttribute}" ItemsSource="{Binding Path=OrderAttributes}">
<StackPanel Name="test" Orientation="Horizontal" VerticalAlignment="Center">
<CheckBox Command="{StaticResource cbc}"
CommandParameter="{Binding Path=NameAndParent}" Visibility="{Binding Path=CheckBoxVisible}" VerticalAlignment="Center">
</CheckBox>
<TextBlock Text="{Binding Path=NameAndCount}" FontSize="16"/>
</StackPanel>
</HierarchicalDataTemplate>
</DockPanel.Resources>
<TreeView Name="treeView1" BorderThickness="2" ItemsSource="{Binding Source={StaticResource MyList}, UpdateSourceTrigger=PropertyChanged}" TreeViewItem.Selected="filterByBatchStatus"/>
</DockPanel>
When A user checks a checkbox in the tree, certain stuff happens in my application based on which checkbox is checked. The way I know which checkbox is being checked is by passing a paramater through a command, and that parameter is bound to the "NameAndParent" of the object. All of this works fine.
My problem begins when I give the user the option to save which checkboxes have been checked and I save the "Name" of each object next to the checked box into an XML. As you can see, I am only saving the "Name" of the object, but this name has no hook to the checkbox, So I can't go back and "find" the associated checkbox.
When I give the user the option to load one of these saved files, I want to traverse the tree and check the boxes that were saved. The problem is that the checkboxes DONT HAVE A NAME, OR UID, and I cant assign them one through binding because that is not allowed.
Is there anyway to traverse the tree view and somehow compare the saved name to the name of each element child in the tree, and then check that specific checkbox, Or is this something that has to be programmed in a different way?
Just create a boolean IsChecked property in the class that contains your Data, and bind the CheckBox.IsChecked to that. instead of having to manipulate the view, you can more easily manipulate the data it is bound to, removing the need for fancy Visual-Tree operations, and removing the dependency between your application logic and your UI. This is the most important realization of the Model-View-ViewModel Pattern.
If you do not want to introduce UI-related logic (such as the IsChecked property I mentioned) into your Data Model, you will have to introduce a ViewModel in between the Model and the View.

Is it possible to bind to a control's property from a datatemplate?

Ok, sounds odd, and there's likely a better way, but I haven't seen it yet.
What I'm trying to do is restyle a ListPicker under Windows Phone 7.
What I need is to
get rid of the header (that's easy, just define a null ListPicker.HeaderTemplate).
Force the picker to always go to full mode when clicked (again, easy, just set the ItemCountThreshold to 1).
Restyle the itemtemplate used when in FullMode (again, easy, just define a FullModeItemTemplate)
Incorporate the ListPicker's "HEADER" property value into the ItemTemplate (since only one item will ever show, i need the header text "embedded" within the one item).
It's that number 4 that I can't seem to get.
I've defined a listpicker like so (i'm directly defining the templates inline instead of in resources for now, just to keep things simple).
<phonekit:ListPicker Header="Header Text" x:Name="ListOfSounds"
SelectedItem="{Binding Path=DepartureChime, Mode=TwoWay, Converter={StaticResource EnumDescriptionToStringConverter}}"
ItemCountThreshold="1">
<phonekit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{TemplateBinding Header}" />
<TextBlock Text="{Binding}" />
<TextBlock Text=">" />
</StackPanel>
</DataTemplate>
</phonekit:ListPicker.ItemTemplate>
Ignoring all the obvious formatting bits for now, the problem I'm having is that I can't use {TemplateBinding Header} from within a datatemplate. I've used it from a ControlTemplate no problem.
The result of this ItemTemplate should be an item displayed such as
{TextOfHeader}{Content of selected Item}>
I'm just not sure how to go about getting at a property of the templated control (the listpicker in this case).
Any ideas?
Take advantages of RelativeSource:
<TextBlock Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType={x:Type phonekit:ListPicker}}}" />

WPF XAML Binding

Hello
I have a problem with a binding that I want to do and can't find any information on how to do it.
Basically I want to bind an object to a property of another object.
For example
<TextBox Text="test" Tag="{Binding ElementName=TxtBx2}" x:Name="TxtBx1"/>
<TextBox Text="test" x:Name="TxtBx2"/>
This is kind of weird but it would help on the code that i'm implementing, so on a property of one object I want to have another object bind in xaml.
I don't know if this is possible, any pointers would be helpful
Thanks, Ruben
That is how you do it; you just need to specify the Path.
<TextBox Text="test" Tag="{Binding ElementName=TxtBx2, Path=Text}" x:Name="TxtBx1"/>
<TextBox Text="test" x:Name="TxtBx2"/>
If you are wanting the DataContext of the TextBox; then your Path would change accordingly.
<TextBox Text="test" Tag="{Binding ElementName=TxtBx2, Path=DataContext}" x:Name="TxtBx1"/>
<TextBox Text="test" x:Name="TxtBx2"/>
If you are needing to use the Tag property within a WPF application you might want to re-evaluate your approach as I have yet to use the Tag property since moving from WinForms as that need has been replaced by leveraging the data binding functionality within WPF.
UPDATE:
If your goal is to bind to a given control versus a property on the control; then don't specify the property name within the Path.
Based on your goal; attached behaviors would be a better approach and allow you to wrap the functionality within the extended DataGrid.
<TextBox Text="test" Tag="{Binding ElementName=TxtBx2,Path=Text}" x:Name="TxtBx1"/>
<TextBox Text="test" x:Name="TxtBx2"/>
Assuming you want the value of the Text property of TxtBx1 to be the value of the Text property in TxtBx2, you would use:
<TextBox x:Name="TxtBx1" Text="{Binding ElementName=TxtBx2, Path=Text}" />
<TextBox x:Name="TxtBx2" Text="test" />
Update
Assuming (possibly incorrectly again!) that you want to bind the TxtBx1 element to the Tag of TxtBx2, you would use:
<TextBox x:Name="TxtBx1" Text="test" />
<TextBox x:Name="TxtBx2" Tag="{Binding ElementName=TxtBx1}" Text="test" />
Just out of interest, why do you want to do such a thing?
Update 2
Assuming that you have a Datagrid that you've extended from the wpftoolkit datagrid and a user control that is a pager for that Datagrid, and when you move to another page you need to do some processing on the datagrid, then why don't you just either update the datagrid in your page change event (if using code behind), or update the items that the datagrid is bound to in your page change verb on your view model (if using MVVM)?
Well, it does make sense to bind to an entire object(not to any specific property) with items control such as this:
<ListBox x:Name="pictureBox"
ItemsSource=”{Binding Source={StaticResource photos}}" …>
......
</ListBox>

Resources