I have a listview with a DataTemplate that has a ComboBox. I want the ComboBox to look flat like a label until the user actually wants to change the value. I had the example below working before, but I changed things around a bit, and now it doesn't work anymore and I'm not sure why.
The IsMouseOver property does not seem to be working correctly, as it only gets set when the mouse is right at the border of the control.
What can I do to make this work correctly?
Here is a snippet:
<CollectionViewSource x:Key="AccountCategories" />
<ControlTemplate x:Key="FlatCombo" TargetType="{x:Type ComboBox}">
<ContentControl
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="4,3,3,3"
/>
</ControlTemplate>
<Style TargetType="{x:Type ComboBox}" x:Key="DropDown">
<Setter Property="OverridesDefaultStyle" Value="False" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="False" />
<Condition Property="IsFocused" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource FlatCombo}" />
</MultiTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="Category">
<ComboBox IsSynchronizedWithCurrentItem="False" Style="{StaticResource DropDown}"
ItemsSource="{Binding Source={StaticResource db}, Path=Categories}" DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding Path=Category}" />
</DataTemplate>
</Window.Resources>
<Grid>
<ListView Margin="0,110,0,0" Name="lstCategories" ItemsSource="{Binding Source={StaticResource AccountCategories}}" Grid.RowSpan="2">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Category" Width="100" CellTemplate="{StaticResource Category}" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Balance}" Header="Balance" Width="100" />
</GridView>
</ListView.View>
</ListView>
I took the code you provided, supplied some data for the collections, and it worked just like you wanted it to. I would suggest using Snoop to look to see if there are any other elements consuming the events you expect the ListView to handle.
Usually when your are having issues with Mouse events firing correctly it's due to the background missing. If the element you expect to receive events has a null reference for a background, the control will not receive the events; only the control underneath of it will. Try setting the background of your ContentControl to "Transparent". That should fix your problem.
Related
I have nearly googled myself to death on this one. I see a lot of solutions to my problem, but none of them are working... I can only assume it is because I am nesting datagrids with checkboxes at the center. Right now my app takes two clicks to change the check state of a checkbox. I assume the first click is to get focus on the appropriate row? or cell and the second click activates the check state change.
Here is my XAML:
<Grid>
<DockPanel ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" VirtualizingPanel.IsContainerVirtualizable="True" >
<TextBox x:Name="textBoxSearch" DockPanel.Dock="Top" Margin="10" TextChanged="TxtFilter_TextChanged" Height="25" MinWidth="250" HorizontalAlignment="Stretch"/>
<DataGrid x:Name="objDatagrid" ItemsSource="{Binding DataView}" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False"
HeadersVisibility="None" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowDetailsVisibilityMode="Visible"
VirtualizingPanel.VirtualizationMode="Recycling">
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="15 0 15 0" IsExpanded="True" HorizontalAlignment="Stretch">
<Expander.Header>
<!-- Control for the expander header text -->
<custom:HighlightTextBlock Text="{Binding Path=Name}"
HighlightPhrase="{Binding ElementName=textBoxSearch, Path=Text}"
HighlightBrush="Lime"/>
</Expander.Header>
<ItemsPresenter HorizontalAlignment="Stretch" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!-- Question Container Textblock. -->
<custom:HighlightTextBlock Text="{Binding QuestionText}" FontWeight="Bold"
HighlightPhrase="{Binding ElementName=textBoxSearch, Path=Text}"
HighlightBrush="Lime"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid x:Name="objInnerDatagrid" ItemsSource="{Binding Answers}" CanUserAddRows="False" CanUserDeleteRows="False"
HeadersVisibility="None" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<CheckBox DockPanel.Dock="Top" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<CheckBox.Content>
<!-- Answer Checkbox Content : Textblock. -->
<custom:HighlightTextBlock Text="{Binding AnswerText}"
HighlightPhrase="{Binding ElementName=textBoxSearch, Path=Text}" HighlightBrush="Lime"/>
</CheckBox.Content>
</CheckBox>
<custom:TestUC Margin="20,10,0,0" HorizontalAlignment="Stretch" Visibility="Collapsed" x:Name="SubQuestionUserControl"/>
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</DockPanel>
</Grid>
I have tried setting styles:
<UserControl.Resources>
<vm:StringToVisibilityConverter x:Key="StringToVisibilityConverter"/>
<BooleanToVisibilityConverter x:Key="BoolToVisibility"/>
<!--<Style TargetType="custom:DataGridWithNavigation" BasedOn="{StaticResource {x:Type DataGrid}}"/>-->
<!--<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
<EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
</Style>-->
<!--<Style x:Key="dataGridStyle" TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>-->
<!--<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="MouseEnter" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>-->
<!--<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>-->
<!--<Style TargetType="DataGridCell">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsReadOnly" Value="False" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="IsEditing" Value="True" />
</MultiTrigger>
</Style.Triggers>
</Style>-->
</UserControl.Resources>
I no longer have the code behind for any of those associated events to show unfortunately.
I have also tried using someone's custom datagrid class references here:
https://stackoverflow.com/a/4827377/5807358
This custom class got me the closest. In fact it worked great... until I needed to un-check that checkbox (located in the inner datagrid). There was no way of changing the check state of an already checked box without first switching to another Row of the main datagrid and then back. I fiddled with trying to customize that class even further to get what I wanted but came up short.
I should also note that I've tried every solution on the stackoverflow link posted above.
Has anyone come across this before? I can post my code-behind if anyone thinks its relevant.
Thanks
I found my answer here! :
http://blog.ditran.net/wpf-datagrid-rowdetailstemplate-double-click-focus-fix/
I'll post the code in case the post ever gets removed:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="SelectRowDetailSection"/>
</Style>
</DataGrid.RowStyle>
Event Handler:
void SelectRowDetailSection(object sender, MouseButtonEventArgs e)
{
var row = sender as DataGridRow;
if (row != null)
{
row.Focusable = true;
row.Focus();
// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;
// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);
// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
// Change keyboard focus.
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}
}
}
The style above needed to be added within the outter . When I added it to the UserControl.Resources section, it did nothing.
I should note that I had to add an additional style to the DataGridRow. With the above code when a row was selected, the row header disappeared. This is likely caused by something on my end. I am using mahapps.metro to style my windows. I bet that might be the culprit.
I have the following XAML code. I want alternate lines in my listview which will be populated dynamically though the code at run time.
I'm using the following XAML code but it give error called Error8 A value of type 'Style' cannot be added to a collection or dictionary of type 'UIElementCollection'.
<ListView Grid.Column="1" Grid.Row="10" BorderBrush="#FFA8CC7B" Height="133" HorizontalAlignment="Left" Margin="0,0,0,93" Name="lstViewAppsList" VerticalAlignment="Top" Width="596"
ItemContainerStyle="{StaticResource alternatingStyle}" AlternationCount="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Apps" Width="150" />
<GridViewColumn Header="Package" Width="350" />
</GridView>
</ListView.View>
</ListView>
<Style x:Key="alternatingStyle" TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="BValue="LightSkyBlue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Orange"/>
</Trigger>
</Style.Triggers>
</Style>
It needs to be in a ResourceDictionary of some sort, you can add to the ListView or the Window/Page resources or even an external resource file
<ListView.Resources>
<Style x:Key="alternatingStyle" TargetType="{x:Type ListViewItem}">
......
</Style>
<ListView.Resources>
So to add it to your example above
<ListView Grid.Column="1" Grid.Row="10" BorderBrush="#FFA8CC7B" Height="133" HorizontalAlignment="Left" Margin="0,0,0,93" Name="lstViewAppsList" VerticalAlignment="Top" Width="596" AlternationCount="2">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
......
</Style>
<ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Apps" Width="150" />
<GridViewColumn Header="Package" Width="350" />
</GridView>
</ListView.View>
</ListView>
You need to place this style in ResourceDictionary. If you are using , Place the style as follows,
<Window.Resources>
<Style x:Key="alternatingStyle" TargetType="{x:Type ListViewItem}">
</Style>
</Window.Resources>
Regards,
Riyaj Ahamed I
I've been searching for quite a while, but cannot figure out how to override the autocomplete functionality in a DataGridComboBoxColumn.
What I want to do is what is explained here, except for a combobox: Searching for items in a list box
That is: I want to be able to enter any string and then apply a filter to the ComboBox items in the DataGridComboBoxColumn to show only those items that match this as a substring.
I'm new to WPF and have been searching online for a while. I've found things like EventSetters and CommandBehaviorCollection.Behaviors, but I can't get a clear picture of the possibilities (and impossibilities).
I've got:
<DataGrid ... >
...
<DataGrid.Columns>
...
<MyCustomDataGridComboBoxColumn Header="My Header" MinWidth="200" >
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.MyData, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<Setter Property="SelectedItem" Value="{Binding DataItem, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True}" />
<Setter Property="DisplayMemberPath" Value="HardwareId" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.MyFilteredData, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<Setter Property="SelectedItem" Value="{Binding DataItem, UpdateSourceTrigger=LostFocus}" />
<Setter Property="DisplayMemberPath" Value="HardwareId" />
<Setter Property="IsEditable" Value="True"/>
<Setter Property="Text" Value="{Binding DataContext.MyNewDataItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</MyCustomDataGridComboBoxColumn>
...
</DataGrid.Columns>
</DataGrid>
Ideally, I'd like to create a new class that inherits from DataGridComboBoxColumn and supply it with some custom logic, such as supplying an anonymous function in its constructor so that the autocomplete behavior can be overridden in different ways in the future.
Is this even possible, or am I going about this entirely the wrong way?
I'm not saying your approach is wrong, however, I would approach it differently. For me it seems easier to use a DataGridTemplateColumn and supply a ComboBox that has the functionality you speak of.
<DataGridTemplateColumn Header="ColumnName" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<YourCustomComboBox/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Edit:
A while ago I needed a ComboBox with the same functionality. I ended up combining a TextBox with a Popup control because it gave me much more control over it.
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" x:Name="editBox"/>
<Popup x:Name="textboxPopup" Width="{Binding ElementName=editBox, Path=ActualWidth, Mode=OneWay}"
PlacementTarget="{Binding ElementName=editBox}"
StaysOpen="False"
IsOpen="{Binding Path=IsOpen, Mode=OneWay}">
<Grid>
<DockPanel MaxHeight="500">
<ListView SelectionMode="Single"
ItemsSource="{Binding Path=Suggestions}"
Name="popupList">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"Color="LightBlue"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="LightBlue"/>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Grid>
In the codebehind I subscribed to the TextChanged event and a few other events that came in handy. I can't share all my code because it is production code. However there are a few other people on the internet with similar implementations: using a ComboBox, using a textbox and of course the link you posted in your question. There is more than enough out there.
And about using your custom control as a TargetType... I don't see anything wrong with that, I do it all the time.
The error with the CellTemplate shouldn't occur. Are you using it correctly? See this link for an example.
Please help on this issue and I'm not sure how to handle this.
I've combox box and datagrid. When ever I've selected combox value datagrid should be loaded with new data and that works perfectly. But I've DataGridTemplateColumn.HeaderTemplate with checkbox when I checked all the column with checkbox is also checked and also worked with unchecked as well. Both are fine.
Now my issue is when i selected combobox, datagrid --> headertemplate checkbox should be unchecked. IS there any event I can fire for this? My code below.
Combox is outside the datagrid.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="checkadded" Margin="6,0" IsChecked="{Binding IsSelected, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Name="ChkAllAdd" IsChecked="False" Width="50" Loaded="chkallLoaded" Checked="ChkAll_Checked" Unchecked="ChkAll_Unchecked" IsThreeState="False" Padding="4,3,4,3" HorizontalContentAlignment="Left" HorizontalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Foreground" Value="#686868"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style TargetType="{x:Type DataGridCell}" >
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="white"/>
<Setter Property="Background" Value="#93A8A9"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
Create a ControlTemplate for Content Control and place your DataGrid and ComboBox Xaml in that. Now you can create an EventTrigger for Combobox and there you can set the CheckedBox Checked using element name in binding. This can be helpfull.
<Window x:Class="EffectsWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<ListView ItemsSource="{Binding EffectsViewModel.Effects}">
<ListView.View>
<GridView>
<GridViewColumn Width="200" Header="Effects">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center"
Text="{Binding Name}"
TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
Effect is just a type has a Name property that returns a string, but the text is still not centered inside its cell.
Any ideas on how to fix it?
You can Stretch the HorizontalContentAlignment for ItemContainerStyle
<ListView ItemsSource="{Binding EffectsViewModel.Effects}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<!--...-->
</ListView>
Update
You should be able to combine the alternating row colors with HorizontalContentAlignment like this. I tried it and it seems to be working
<ListView ItemsSource="{Binding EffectsViewModel.Effects}"
AlternationCount="2">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightBlue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightGray"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<!--...-->
</ListView>
Try using an app like snoop to visually inspect the properties of your app and you can see where things are not aligning like you expect.