WPF RowValidation column of DataGrid placement - c#

Is it possible to place RowValidation column not at the left side? For example, at the right side or somewhere else?
How it looks:
How I want it to looks:

While I can't confirm this 100%, I don't think that your requirements are possible. There is a DataGrid.RowValidationErrorTemplate property which enables you to define a custom template to display when validation errors occur, but it does not enable you to specify the placement of it. According to the DataGrid.RowValidationErrorTemplate Property page on MSDN:
The following example replaces the default row validation feedback with a more visible indicator. When a user enters an invalid value, a red circle with a white exclamation mark appears in the row header.
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
<Grid Margin="0,-2,0,-2"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}">
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>

Related

How to add a border around the entire DataGrid column header?

I've customized the DataGrid a lot, but surprisingly I'm unable to add a border around the entire header area without it breaking.
So this is what I'm trying to accomplish:
The following control is responsible for displaying the header area: DataGridColumnHeadersPresenter.
I added a border around it, and as you can see from the screenshot above, it does work, but the problems begin only when the grid is empty! (this means that also the empty row needs to be removed, which can be done by setting CanUserAddRows="False").
So far, here's my style:
<Border BorderBrush="Red" BorderThickness="1" Grid.Column="1">
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Margin="0,0,0,5"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
</DataGridColumnHeadersPresenter>
</Border>
All I did was wrap it with a border, but now when I apply filtering so that the grid is empty, the header disappears to the right and the application slows down to a crawl.
Demonstration:
If I remove the border, everything works as expected. It seems like the DataGrid is expecting a very specific tree structure, otherwise it just explodes.
I tried changing the template of the DataGridColumnHeadersPresenter, but also that expects a very specific structure which looks like this:
<DataGridColumnHeadersPresenter.Template>
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid>
<DataGridColumnHeader x:Name="PART_FillerColumnHeader"
IsHitTestVisible="False" />
<ItemsPresenter />
</Grid>
</ControlTemplate>
</DataGridColumnHeadersPresenter.Template>
If I give the DataGridColumnHeader a BorderBrush and BorderThickness, it doesn't look right, and if I add my own border control anywhere, the same problem arises.
The DataGridColumnHeadersPresenter actually has BorderBrush and BorderThickness properties, but they have no effect at all.
One workaround I found was to set Grid.Column to 0 so that it goes in place of the row headers column header, then just set HeadersVisibility="Column" on the DataGrid so it doesn't look broken, and the problem disappears. Unfortunately I need the row headers, so this is an unacceptable solution.
Default style for DataGrid can be found here, or just right-click it in Visual Studio and go to Edit Template, then Edit a Copy, which is what I did.
There must be an easy way to accomplish this that I'm probably just not seeing right now...
Ok so I just returned to tackle this problem after #jsanalytics pointed out the existence DataGridHeaderBorder, and by analyzing the default tree structure more deeply, with a little bit of trial and error, I managed to get the job done.
I did not want the DataGridHeaderBorder though, which is part of the Windows themes, but replaced it with a regular border.
My implementation:
<DataGridColumnHeadersPresenter Grid.Column="1" x:Name="PART_ColumnHeadersPresenter"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
<DataGridColumnHeadersPresenter.Template>
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid HorizontalAlignment="Left">
<ItemsPresenter />
<DataGridColumnHeader x:Name="PART_FillerColumnHeader" IsHitTestVisible="False">
<DataGridColumnHeader.Template>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Border BorderThickness="2" BorderBrush="Red">
<ContentPresenter RecognizesAccessKey="True"
SnapsToDevicePixels="True" />
</Border>
<!--Uncomment if you need these resizing grippers-->
<!--<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" />-->
</Grid>
</ControlTemplate>
</DataGridColumnHeader.Template>
</DataGridColumnHeader>
</Grid>
</ControlTemplate>
</DataGridColumnHeadersPresenter.Template>
</DataGridColumnHeadersPresenter>
You'll probably need to tweak it for your own needs, but this fills our requirements :-)

WPF Listbox items with name on mouseover or active

I've tried several different solutions to this, but can't land on one that meets all of my needs.
We have an observable collection of objects that each have a status and a name. It's a sort of task-list of running items. To display this list in WPF, we have some code that represents each item as an ellipse with some colors and animations.
The problem is that we want to display the name of the item as a 'popup' both on mouseover, or when the task is in a given state.
Attempt #1
My first attempt implemented this as a Datatemplate (to be used as an ItemTemplate) with an actual WPF Popup. I implemented two datatriggers - one for mouseover and one for task state. I positioned the popup based on my ellipse and everything was great. However, moving the window or switching to a different window left the popup on top of everything.
Attempt #2
Instead of using the popup I used a textbox in a canvas. This works great until the Datatemplate is used in the Listbox. The item host (stackpanel) ends up clipping the string.
Here's example code:
<DataTemplate x:Key="EllipseTemplate">
<Grid Height="40" Width="40">
<Canvas Name="PopupCanvas" HorizontalAlignment="Center" Width="500">
<TextBlock Name="PopupName"
Width="{Binding ElementName=PopupCanvas, Path=ActualWidth}"
Text="{Binding}"
Background="Transparent"
FontSize="16" HorizontalAlignment="Center" TextAlignment="Center" FontWeight="Bold"
Canvas.Top="-25"
Visibility="Collapsed"
/>
</Canvas>
<Ellipse x:Name="Ellipse" Height="25" Width="25" Margin="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
Fill="Green"
RenderTransformOrigin="0.5, 0.5" StrokeThickness="0.5" Stroke="Black">
</Ellipse>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PopupName" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<Grid Name="Test" Background="LightGoldenrodYellow" ClipToBounds="False" Margin="50">
<ListBox Name="OverlayTest"
Background="CornflowerBlue"
BorderThickness="0"
VerticalAlignment="Center"
Margin="10"
ClipToBounds="False"
ItemTemplate="{StaticResource EllipseTemplate}">
<sys:String>Very long string that will get clipped</sys:String>
<sys:String>Two</sys:String>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True" Margin="10,50,10,50" ClipToBounds="False"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
Attempt #3
I moved my canvas/textbox outside of the datatemplate and create a grid to put it above the listbox of ellipses. This works from a layout perspective, but creates a big mess in terms of checking for mouseover and centering the textbox on the control that's active/hovered.
So that leaves me without an implementation that works the way I want. Anyone have any suggestions?
Ok here I have another idea. I had problem with the ListBox before. Try replacing the ListBox with an ItemsControl.
Attempt #2 sounds like is working fine. You should be able to solve the issue of the clipping using one of these solutions (or all of them):
Set the ClipToBounds property of the ListBox to false
Set the ClipToBounds property of the Stackpanel to false

Bind to child element of content template by name from outside

How can I get the binding from the outer ConnectingLine (a custom control that binds to FrameworkElements and connects them with a line) to the inner TextBlocks named "Top" and "Bottom" to work? Note that I want the whole FrameworkElements for position information.
<Grid>
<ConnectingLine From="{Binding ElementName=Button1.Top}" To="{Binding ElementName=Button2.Top}" />
<ConnectingLine From="{Binding ElementName=Button1.Bottom}" To="{Binding ElementName=Button2.Bottom}" />
<ToggleButton x:Name="Button1">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Rectangle x:Name="Top" />
<Rectangle x:Name="Bottom" />
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ToggleButton x:Name="Button2">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Rectangle x:Name="Top" />
<Rectangle x:Name="Bottom" />
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</Grid>
My goal is to be able to bind from within XAML. Ideally with no extra fluff, but a solution involving a custom binding operator or attached properties might be acceptable.
Edit:
How I'd like to have the output:
Each distinct colored column is one of the templated ToggleButtons, already with one dashed ConnectingLine between Top and Bottom elements. The horizontal filled lines are what I'm interested in. Currently I'm achieving what I want from code-behind.
<ToggleButton x:Name="Button">
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<CheckBox x:Name="FindMe" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked}"/>
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
Let me know if it works.

Default template for ComboBox: How does IsEditable switch TextBox and Contentpresenter

I am using ComboBox in WPF but there is one behavior that I don't understand: here is the link of the default style/template of ComboBox . When IsEditable is True, the TextBox shows and the user can type text to search. I didn't quite understand this so I was checking the code:
<ContentPresenter x:Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Stretch"
HorizontalAlignment="Left">
</ContentPresenter>
<TextBox x:Name="PART_EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}" />
It seems there are two visual components overlapping and IsEditable switches between them by setting the Visibility. This link verifies that: "When IsEditable is equal to false, the ComboBox uses a ContentPresenter to display the currently selected item; when IsEditable is equal to true, a TextBox is used for this purpose instead. Note that a TextBox only displays plain text, and that a ComboBoxItem may include non-plain text content, such as images." My question is, in the TextBox, where does it define the text? The Template (ComboBoxTextBox) doesn't assign the Text. I was asking because I am trying to make the TextBox to display the same info (if that's ever possible) as the ContentPresenter (i.e., as when IsEditable is False), whose template I understand is binding to the Template I assign.
here is a bare basic template for textbox for you with just the text editing part
so setting IsReadOnly="True" will make it like a ContentPresenter otherwise it is editable like a textbox
<TextBox Text="edit me">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<ScrollViewer x:Name="PART_ContentHost" />
</ControlTemplate>
</TextBox.Template>
</TextBox>
you can customize it for your needs

Looking for a control to repeat a certain template

Greetings,
I'm looking for a way in Silverlight to have a control which repeats a template for each item bound to it.
I'll try to explain a bit better.
http://img51.imageshack.us/i/naamloosmb.png/
in the screenshot you see a few of the lessons available.
The list contains: "Zumba, Squash, Spinning, Spinning Marathon, Personal Trainer (PT) Sessies" etc
Each item has a description, a picture and a button to go to the page for the corrosponding lesson.
Does anyone know if there is a control available which allows me to achieve this?
If not, how should I start to accomplish this?
Why not use a listbox and an itemtemplate?
Here is a great tutorial: http://backissues.code-magazine.com/article.aspx?quickid=112091&page=1
Basically you can use a Setter to define an item template (remember in Silverlight/WPF an item's content can be any object) with a layout inside.
E.g.
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Height="30" Width="30"
Margin="2"
Fill="{Binding Logo}" />
<Label Content="{Binding Name}"
VerticalAlignment="Center"
FontSize="14" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
Producing:

Categories