How to design this ListViewItem - c#

I want my ListViewItem to look like this. As you can see when the ListViewItem is selected/has focus the Border should change color.
The Main Problem is that I can't put a Border around the ContenPresenter in the ControlTemplate because than also the TextBox with the "Description"-Binding will be inside the Border. But I only want the TextBox and Icon to be inside the Border that changes Colors and not also the Description ("Nachname", "Vorname").
This is the XAML I have so far. I don't know how to change the border in the ControlTemplate:
<ListView x:Name="SearchFields" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding CustomerSearchFields}" SelectedItem="{Binding selectedSearchField, UpdateSourceTrigger=LostFocus}" Style="{StaticResource MaterialDropShadowStyle}"
BorderThickness="0,0,2,0" Padding="24,24,24,0" HorizontalContentAlignment="Stretch" helper:EnterKeyTraversal.IsEnabled="True" KeyboardNavigation.TabNavigation="Cycle" FontFamily="{StaticResource DefaultFontFamily}"
Background="{StaticResource ColorLightGray2}">
<ListView.Resources>
<DataTemplate DataType="{x:Type model:CustomerSeachFieldViewModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Description}" FontSize="{StaticResource FontSizeSmall}" FontWeight="SemiBold" Foreground="{StaticResource ColorDarkGray}" Margin="0,0,0,4" />
<Border x:Name="PART_Border" Grid.Row="1" BorderThickness="1" BorderBrush="{StaticResource ColorGray}">
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="48" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding SearchText}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" FontSize="{StaticResource FontSizeNormal}" Padding="12,15" BorderThickness="0" />
<Border Grid.Column="1" Background="{StaticResource ColorLightGray2}" Margin="8">
<ctrl:IconViewbox IconData="{StaticResource IconPathSearch}" IconSize="16" IsTabStop="False" />
</Border>
</Grid>
</Border>
</Grid>
</DataTemplate>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Margin" Value="0,0,0,24" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentPresenter Content="{Binding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="BorderBrush" Value="Fuchsia" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>

You can add a Trigger to your Border named PART_Border as follow:
<Border x:Name="PART_Border" Grid.Row="1" BorderThickness="1" >
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Value="True" >
<Setter Property="BorderBrush" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="48" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Text="{Binding SearchText}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" FontSize="15" Padding="12,15" BorderThickness="0" />
<Border Grid.Column="1" Background="Gray" Margin="8">
<Rectangle Width="20" Height="20" />
</Border>
</Grid>
</Border>
Please note that I replaced some StaticResource mapped to some Colors from your code with standard color in order to test my code.
I also replaced the icon with a Rectangle for the same reason.

Try for your IsSelected trigger:
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="PART_Border" Property="BorderBrush" Value="Fuchsia" />
<Setter TargetName="PART_Border" Property="BorderThickness" Value="1" />
</Trigger>

You could add a Style with a DataTrigger that binds to the IsSelected property of the parent ListViewItem to the Border in your DataTemplate:
<Border x:Name="PART_Border" Grid.Row="1" BorderThickness="1">
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="{StaticResource ColorGray}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"
Value="True">
<Setter Property="BorderBrush" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
Note that you need to set the default value of the property ({StaticResource ColorGray}) using a Style setter for the DataTrigger to be able to set the property when the ListViewItem is selected.

Related

Change Background Color of SelectedItem from WPF ListView with Custom DataTemplate

I have a ListView Control in WPF which displays a list of boxes from which the user can select one from the collection. What I'm currently trying to accomplish is to have Selected Item's Background Property changed to a different color for a proper identification.
I found a Code Snippet which partially solves my problem, however, the Background value of the SelectedItem reverts back to its original when I press anywhere within the module.
What I'd like to happen is for the Background value to persist for the SelectedItem regardless if I press on other controls or even if the Window gets unfocused.
Below is my XAML Code Snippet with the Setters and Triggers I currently have in place.
<ListView Grid.Row="2"
ItemsSource="{Binding FakeDispatchBoxCollection}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<md:Card Margin="0,0,0,10"
Cursor="Hand">
<md:Card.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" Value="true">
<Setter Property="md:Card.Background" Value="LightGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</md:Card.Style>
<Grid Margin="5">
<!--#region Row & Column Definitions -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.60*" />
<ColumnDefinition Width="0.40*" />
</Grid.ColumnDefinitions>
<!--#endregion-->
<Label Grid.Row="0" Grid.Column="0"
Content="{Binding DispatchBoxName}"
FontWeight="ExtraBlack"
FontSize="15"
FontFamily="Baloo Bhai 2" />
<Label Grid.Row="1" Grid.Column="0"
Content="{Binding DispatchBoxType}"
FontWeight="SemiBold"
FontSize="13"
FontFamily="Baloo Bhai 2" />
<Label Grid.Row="0" Grid.Column="1"
Grid.RowSpan="2"
Content="{Binding UnitCount}"
VerticalAlignment="Center"
HorizontalAlignment="Right"
FontWeight="ExtraBlack"
FontSize="20"
FontFamily="Baloo Bhai 2" />
</Grid>
</md:Card>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In the Item's Data Template (ItemTemplate property), you don't have any items that can accept keyboard focus. There are only Labels.
And in the ListViewItem Template Trigger (ItemContainerStyle property), you set the IsSelected property dependency on the keyboard focus inside the ListViewItem.
Also, you shouldn't use a ListView if you don't specify columns. In this case it is better to use ListBox.
An example of a correct implementation:
<Window.Resources>
<!--To simplify the example.-->
<CompositeCollection x:Key="source">
<sys:String>First</sys:String>
<sys:String>Second</sys:String>
<sys:String>Third</sys:String>
<sys:String>Fourth</sys:String>
</CompositeCollection>
</Window.Resources>
<ListBox ItemsSource="{DynamicResource source}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label x:Name="label" Content="{Binding}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="true">
<Setter TargetName="label" Property="Background" Value="Coral" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>

How to set Combobox dropdown list width to the Combobox it belongs to?

See picture below, how to align dropdown list border to the actual combo box?
https://imgur.com/uNO45F2
Here is the code for Combobox, which uses customized ComboBoxItem style,
<ComboBox Grid.Row="0" Grid.Column="0" ItemsSource="{Binding ASDevicesView, Mode=OneWay , UpdateSourceTrigger=PropertyChanged}" AutomationProperties.AutomationId="4314"
SelectedItem="{Binding SDevice}" IsEditable="True" Text="{Binding SearchText}" MaxDropDownHeight="166" ItemContainerStyle="{StaticResource MyComboBoxItemStyle}">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsDropDownOpen" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
Here is the code for ComboBoxItem style,
<Style x:Key="MyComboBoxItemStyle" BasedOn="{StaticResource {x:Type ComboBoxItem}}" TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}" />
<Setter Property="Height" Value="40" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Grid Background="Transparent" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="36"/>
<ColumnDefinition Width="AUTO"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="AUTO"/>
</Grid.RowDefinitions>
<Image Source="{Binding Icon}" Width="12" Height="12" Margin="3,3,3,3" Grid.Row="0" Grid.Column="0"/>
<TextBlock Text="{Binding DName}" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I think the problem is that the ComboBox is not the TemplatedParent of the ComboBoxItem (indeed it was pointed out e.g. in this comment), so better to search it explicitly:
<Setter Property="Width" Value="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=ActualWidth}" />

DataGrid Column Header with filter box binding error

After trying for some days I stripped my project down to the minimum to attach it here to my question.
I want to add a text filter box to my WPF datagrid header.
But I get these error messages:
System.Windows.Data Error: 40 : BindingExpression path error: 'TextFilterData' property not found on 'object' ''DataGridColumnHeader' (Name='PART_FillerColumnHeader')'. BindingExpression:Path=TextFilterData; DataItem='DataGridColumnHeader' (Name='PART_FillerColumnHeader'); target element is 'TextBox' (Name='PART_TextFilter'); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'TextFilterData' property not found on 'object' ''DataGridColumnHeader' (Name='')'. BindingExpression:Path=TextFilterData; DataItem='DataGridColumnHeader' (Name=''); target element is 'TextBox' (Name='PART_TextFilter'); target property is 'Text' (type 'String')
The datagrid in my application:
<Grid>
<local:MyDataGrid x:Name="myDataGrid">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Width="64"
Binding="{Binding Path=id, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=''}"
local:DataGridColumnExtensions.TextFilterData="{Binding Path=FilterId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="ToolTip" Value="The ID of the person"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<!-- The filter data will be replaced by property binding in the real application. Here I'm using a fix value for the sake of simplicity -->
<DataGridTextColumn Header="Name" Width="400"
Binding="{Binding Path=name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=''}"
local:DataGridColumnExtensions.TextFilterData="{Binding Path=FilterName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="ToolTip" Value="The name of the person"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</local:MyDataGrid>
</Grid>
I'm using an extension class to create the dependency property for the text filter content
public class DataGridColumnExtensions
{
public static readonly DependencyProperty TextFilterDataProperty = DependencyProperty.RegisterAttached("TextFilterData", typeof(string), typeof(DataGridColumn), new FrameworkPropertyMetadata(String.Empty));
public static string GetTextFilterData(DependencyObject target)
{
return (string)target.GetValue(TextFilterDataProperty);
}
public static void SetTextFilterData(DependencyObject target, string value)
{
target.SetValue(TextFilterDataProperty, value);
}
}
And here is the datagrid style I'm using. I tried to remove everything not needed for the sake of simplicity.
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border x:Name="BackgroundBorder" BorderThickness="0,1,0,1" Background="Gray" BorderBrush="DarkGray" Grid.ColumnSpan="2" />
<ContentPresenter Margin="3" VerticalAlignment="Center" />
<Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill" Grid.Column="1" Width="8" Height="6" Fill="White" Margin="0,0,8,0" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" />
<TextBox x:Name="PART_TextFilter"
Grid.Row="1" Margin="1,0,1,4"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}}, Path=Column.TextFilterData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource Style_HeaderGripper}"/>
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource Style_HeaderGripper}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="{x:Null}">
<Setter TargetName="BackgroundBorder" Property="Background" Value="Transparent" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="Transparent" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="BackgroundBorder" Property="Background" Value="LightGray" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="Gray" />
</Trigger>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:MyDataGrid}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyDataGrid}">
<Border Background="{TemplateBinding Background}">
<ScrollViewer Focusable="false" Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="3" Background="Gray" BorderBrush="DarkGray" BorderThickness="0,1" />
<Button Command="{x:Static DataGrid.SelectAllCommand}" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=RowHeaderActualWidth}" Focusable="false" OverridesDefaultStyle="True"/>
<DataGridColumnHeadersPresenter Grid.Column="1"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=HeadersVisibility,
Converter={x:Static DataGrid.HeadersVisibilityConverter},
ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
<ScrollContentPresenter Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
What is missing to get the filter content binding working?
Any help is highly appreciated.
2016-08-10: Update with first fix
In the Header ControlTemplate, you're using RelativeSource Self inside the TextBox
<TextBox x:Name="PART_TextFilter"
...
Text="{Binding RelativeSource={RelativeSource Self}, Path=TextFilterData, ...}"/>
The error message states there's no TextFilterData property on this TextBox.
Try
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}},
Path=Column.TextFilterData, ...}"/>

Alternating Background Color Grid Rows not working

I am trying to implement alternating background Color on my Rows.
I have an ItemsControl with an ItemTemplate in which I use Triggers on the Style Property of the Border.
But I end up with all RoyalBlue Rows instead of alternating with Red.
Can somene assist? Thank you very much!
<Page.Resources>
<DataTemplate x:Key="myTemplate" >
<Grid>
<Border BorderThickness="1" CornerRadius="2" Margin="2" VerticalAlignment="Stretch" Height="20" Width="Auto">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Red" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="RoyalBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="{Binding Name}"/>
</Grid >
</Border>
</Grid>
</DataTemplate>
</Page.Resources>
<ScrollViewer >
<StackPanel >
<ItemsControl ItemsSource="{Binding Path=myElements}" ItemTemplate="{StaticResource myTemplate}" AlternationCount="2"/>
</StackPanel>
</ScrollViewer>
ItemsControl.AlternationIndex will be set against direct child of ItemsControl panel (ContentPresenter) so you need to use DataTrigger with RelativeSource binding and because it's an attached property you need to put in brackets like Path=(ItemsControl.AlternationIndex)
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0">
<Setter Property="Background" Value="RoyalBlue" />
</DataTrigger>
</Style.Triggers>
</Style>

SelectedRow of datagrid is not selected again after returning to same Page

I have two different Pages called Select and Edit. Both of them shares same ViewModel named SalesAccountsViewModel.
I have a DataGrid in Select Page as follows:
Then I select it any Item from the DataGrid :
Then I click on edit button on selected row as shown below:
After that I am redirected to another Page as shown below:
When I click on save button:
I am again redirected to the Previous Page but can you see the first row? It is not Highlighted fully:
Here is Select Page that I use:
<Page x:Class="MiniAccountWPF.Views.Pages.Masters.SalesAccounts.Select"
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"
xmlns:vm="clr-namespace:MiniAccountWPF.ViewModels.Masters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Select" DataContext="{StaticResource salesAccountsViewModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Margin="0,10" HorizontalAlignment="Left"
Content="{Binding SelectedChildMenuItem.MenuItemName, Converter={StaticResource createButtonContentConverter}, Source={StaticResource mainWindowViewModel}}" />
<DataGrid Grid.Row="1" ItemsSource="{Binding Ledgers}" SelectedValue="{Binding SelectedLedger}"
IsReadOnly="True" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Customer Name" Binding="{Binding LedgerName}" />
<DataGridTextColumn Header="City" Binding="{Binding City}" />
<DataGridTemplateColumn Header="Mobile Numbers">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding MobileNo1, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=N}" />
<Run Text="{Binding MobileNo1, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=S}" FontFamily="Consolas"/>
<Run Text=" " FontFamily="Consolas"/>
<Run Text="{Binding MobileNo2, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=N}" />
<Run Text="{Binding MobileNo2, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=S}" FontFamily="Consolas"/>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Opening Balance" Binding="{Binding OpeningBalance}" />
<DataGridTemplateColumn Header="Edit">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Edit" Style="{StaticResource EditButton}"
Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" Style="{StaticResource DeleteButton}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Page>
Here is the Edit Page:
<Page x:Class="MiniAccountWPF.Views.Pages.Masters.SalesAccounts.Edit"
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"
xmlns:vm="clr-namespace:MiniAccountWPF.ViewModels.Masters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Edit" DataContext="{StaticResource salesAccountsViewModel}">
<Grid DataContext="{Binding SelectedLedger}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="350" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Name" Style="{StaticResource txtBlock}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
<TextBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="3" Text="{Binding LedgerName}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text="City" Style="{StaticResource txtBlock}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
<TextBox Grid.Row="3" Grid.Column="2" Text="{Binding City}"/>
<TextBlock Grid.Row="5" Grid.Column="1" Text="Mobile No." Style="{StaticResource txtBlock}"/>
<TextBlock Grid.Row="5" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
<TextBox Grid.Row="5" Grid.Column="2" Text="{Binding MobileNo1}"/>
<TextBox Grid.Row="5" Grid.Column="4" Text="{Binding MobileNo2}"/>
<TextBlock Grid.Row="7" Grid.Column="1" Text="Opening Balance " Style="{StaticResource txtBlock}"/>
<TextBlock Grid.Row="7" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
<TextBox Grid.Row="7" Grid.Column="2" Text="{Binding OpeningBalance}"/>
<Grid Grid.Row="10" Grid.Column="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Content="Save"
Command="{Binding DataContext.EditSaveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>
<Button Grid.Column="3" Content="Cancel" HorizontalAlignment="Left"
Command="{Binding DataContext.EditCancelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>
</Grid>
</Grid>
</Page>
The ViewModel:
namespace MiniAccountWPF.ViewModels.Masters
{
public class SalesAccountsViewModel: ViewModelBase, IModule
{
public SalesAccountsViewModel()
{
SessionViewModel.Instance.ModulesOpen.Add((IModule)this);
using (MiniAccountDBEntities db = new MiniAccountDBEntities())
{
Ledgers = new ObservableCollection<Ledger>(db.Ledgers.Where(x => x.LedgerType.LedgerTypeName == "Customer"));
}
EditCommand = new RelayCommand(Edit_Click);
EditSaveCommand = new RelayCommand(Edit_Save_Click);
EditCancelCommand = new RelayCommand(Edit_Cancel_Click);
}
~SalesAccountsViewModel()
{
SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
}
private ObservableCollection<Ledger> _ledgers;
public ObservableCollection<Ledger> Ledgers
{
get
{
return _ledgers;
}
set
{
_ledgers = value;
OnPropertyChanged("Ledgers");
}
}
private Ledger _selectedLedger;
public Ledger SelectedLedger
{
get
{
return _selectedLedger;
}
set
{
_selectedLedger = value;
OnPropertyChanged("SelectedLedger");
}
}
public ICommand EditCommand { get; set; }
private void Edit_Click(object obj)
{
var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.EditFrameNavigationURL;
}
public ICommand EditSaveCommand { get; set; }
private void Edit_Save_Click(object obj)
{
using (MiniAccountDBEntities db = new MiniAccountDBEntities())
{
Ledger ledger = db.Ledgers.Single(x => x.LedgerID == SelectedLedger.LedgerID);
ledger.LedgerName = SelectedLedger.LedgerName;
ledger.City = SelectedLedger.City;
ledger.MobileNo1 = SelectedLedger.MobileNo1;
ledger.MobileNo2 = SelectedLedger.MobileNo2;
ledger.OpeningBalance = SelectedLedger.OpeningBalance;
db.SaveChanges();
var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.SelectFrameNavigationURL;
}
}
public ICommand EditCancelCommand { get; set; }
private void Edit_Cancel_Click(object obj)
{
var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.SelectFrameNavigationURL;
}
public string ModuleFriendlyName
{
get { return "SalesAccountsViewModel"; }
}
public string ModuleName
{
get { return "SalesAccounts"; }
}
}
}
Styles applied to DataGrid in ResourceDictionary:
<Style TargetType="{x:Type DataGrid}">
<Setter Property="GridLinesVisibility" Value="Vertical" />
<Setter Property="RowHeaderWidth" Value="0" />
</Style>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="{StaticResource BrushHeaderBackground}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="10" />
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="1,0" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="CanUserSort" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="{StaticResource BrushOrangeSelector}" />
</MultiTrigger.Setters>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsPressed" Value="True" />
<Condition Property="CanUserSort" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Gray" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="10" />
<Setter Property="FontSize" Value="16" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType='{x:Type DataGridRow}'>
<Setter Property="Background" Value="Gray" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
</Trigger>
</Style.Triggers>
</Style>
the issue was view model, which was getting created with every view, leading to multiple copies of person collection
so I did place a property for VM in ServiceLocator for single instance and initialized the same
public ListViewModel ListViewModel {get; set;}
then I replaced the declaration of view model from the list view to point to this property
DataContext="{Binding ListViewModel, Source={x:Static vm:ServiceLocator.Instance}}"
this solves the problem of multiple instance of the collection but again datagrid has some problem redoing the selection so I added a style with datatrigger to reapply the selection
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter Property="Background"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
this trigger will ensure the row looks selected even if the page is reloaded.
here is a working sample
EDIT
here is a solution for the issue after merging Metro.xaml
remove DataGrid.RowStyle from the DataGrid in ListView and replace the mentioned styles in Metro.xaml with these
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="16" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType='{x:Type DataGridRow}'>
<Setter Property="TextElement.Foreground" Value="White" />
<Setter Property="Background" Value="Gray" />
<Setter Property="Height" Value="50" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FFE1AF4D" />
<Setter Property="TextElement.Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
It might have lost focus. I have seen similar problems where WPF controls are partially rendered.
Try putting the focus back to the target grid control.

Categories

Resources