WPF conditional datagrid grouping - wpf

I have a DataGrid with grouping based on customer name, and it works.
<GroupBox Header="{Binding ElementName=MainWindow, Path=ocS3FileListCount}" ContentStringFormat="" Name="grpRemote" Margin="5,0,0,0" Grid.Column="1" Grid.Row="2">
<GroupBox.Resources>
<CollectionViewSource x:Key="S3List" Source="{Binding ElementName=MainWindow, Path=ocS3FileList}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="CustomerName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</GroupBox.Resources>
<DataGrid x:Name="dgS3List" Margin="0,0,0,0" ItemsSource="{Binding Source={StaticResource S3List}}" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="File Name" Width="*" Binding="{Binding Path=FileName}" IsReadOnly="True" />
<DataGridTextColumn Header="Received" Width="100" Binding="{Binding Path=JobReceived,StringFormat=d}" IsReadOnly="True" Stylus.IsPressAndHoldEnabled="True" />
<DataGridTextColumn Header="Date" Width="100" Binding="{Binding Path=JobDate,StringFormat=d}" IsReadOnly="True" Stylus.IsPressAndHoldEnabled="True" />
</DataGrid.Columns>
</DataGrid>
</GroupBox>
I do have a few users that would like the option to turn grouping on and off for different uses.
I've used conditional styles before based on the status of a different control, but is it possible to have a conditional GroupStyle?
Having it enabled based on a toolbar checkbox seems like a good solution:
<CheckBox x:Name="chkGroupSwitch" IsChecked="True">Enable Grouping</CheckBox>

I don't know about a way to make your GroupStyle style conditional in XAML, but since the GroupStyle only applies if you have a GroupDescription in your ViewSource, I would use a different approach:
The solution in C# is simple. All you have to do is add/remove the ViewSource's PropertyGroupDescription whenever the state of your checkbox changes.
eg.
private void ToggleGroupingEnabled(bool mode)
{
CollectionViewSource viewSource = grpRemote.Resources["MyViewSourceName"] as CollectionViewSource;
viewSource.GroupDescriptions.Clear();
if (mode)
{
var groupDesc = new PropertyGroupDescription("CustomerName");
viewSource.GroupDescriptions.Add(groupDesc);
}
}
Assuming your ViewSource has a name:
<CollectionViewSource x:Key="S3List" x:Name="MyViewSourceName" Source="{Binding ElementName=MainWindow, Path=ocS3FileList}">

Related

WPF DataGrid TemplateColumn not switching between edit and normal templates

I have a WPF DataGrid and I am trying to display a TextBlock when not in edit mode and a ComboBox when editing. I would think this would be easy, but it is not. I can only get it to working using a brute force method of placing the controls in a Grid and using a Visibility binding to show the controls in turn; which is a real pain.
Why does the following not work:
I can get one or the other to show, but not both based on cell editing.
<DataGrid Background="DarkGray" ItemsSource="{Binding Items}" CanUserAddRows="false" AutoGenerateColumns="False"
ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionChanged="DataGrid_SelectionChanged" SelectedIndex="{Binding SelectedIndex}"
behaviors:DataGridBehavior.OnSelectAction="{Binding Path=OnSelectionChanged}">
<DataGrid.Columns>
<DataGridTextColumn Header="Button" Binding="{Binding Button}" />
<DataGridTextColumn Header="Button Display" Binding="{Binding ButtonDisplay}" />
<DataGridTextColumn Header="Reason Code" Binding="{Binding ReasonCode}" />
<!--<DataGridTextColumn Header="Count Stamps" Binding="{Binding CountStamps}" />-->
<DataGridTemplateColumn Header="Count Stamps">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True" SelectedValue="{Binding CountStamps}"
ItemsSource="{Binding Values}" DisplayMemberPath="Name" SelectedValuePath="Value" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CountStamps}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*" />
</DataGrid.Columns>

DataGrid sorting doesn't work

I have a TabControl that has one TabItemwith a DataGrid inside.
<TabControl Background="{DynamicResource StandardBackgroundColor}"
Grid.Row="2" Grid.Column="1"
BorderBrush="{DynamicResource StandardBorderColor}"
DataContext="{Binding ChartViewModel}">
<TabItem Header="{lex:Loc Data}">
<DataGrid Name="TagGrid" ItemsSource="{Binding UnionAllSerie}"
ColumnWidth="*" Background="#CCCCCC">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="{lex:Loc time}" SortDirection="Descending"
Binding="{Binding X, Converter={StaticResource OleDateToDateTimeConverter}, StringFormat=\{0:dd/MM/yy HH:mm\}}" />
<DataGridTextColumn Header="{lex:Loc Measure}"
Binding="{Binding Y}" />
</DataGrid.Columns>
</DataGrid>
</TabItem>
Where my UnionAllSerie is declared as follow:
public ObservableCollection<Data> UnionAllSerie { get; set; } = new ObservableCollection<Data>();
This collection of data is populated depending on the action performed on the window. What I want is to have the Grid automatically sorted by the second column, which represents the date.
Does anybody know what I am doing wrong or missing?
Thanks!
Setting the SortDirection on a Datagrid column does not actually sort the column. (see here for details).
I would recommend using a CollectionViewSource which has build in functionality for your purpose.
The result should look something like this:
<Window.Resources>
<CollectionViewSource x:Key="UnionAllSerieViewSource" Source="{Binding UnionAllSerie}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="X" Direction="Descending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
...
<DataGrid Name="TagGrid" ItemsSource=""{Binding Source={StaticResource UnionAllSerieViewSource}}""
ColumnWidth="*" Background="#CCCCCC">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="{lex:Loc time}" SortDirection="Descending"
Binding="{Binding X, Converter={StaticResource OleDateToDateTimeConverter}, StringFormat=\{0:dd/MM/yy HH:mm\}}" />
<DataGridTextColumn Header="{lex:Loc Measure}"
Binding="{Binding Y}" />
</DataGrid.Columns>
</DataGrid>
For more information on how to sort CollectionViewSources see this msdn article.

Showing Hiding a control inside datagrid in silverlight with MVVM

I have a datagrid like below
**strong text**
<sdk:DataGrid AutoGenerateColumns="False" Height="Auto" MaxHeight="500"
HorizontalAlignment="Left" Margin="5" Name="_EmployeeGrid"
ItemsSource="{Binding Path= Employees,Mode=TwoWay}"
HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Visibility="Visible"
VerticalAlignment="Top" Width="Auto">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Employee ID" IsReadOnly="True" Binding="{Binding Path=EmpID}"/>
<sdk:DataGridTemplateColumn Header="Name" SortMemberPath="EmpID">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<HyperlinkButton VerticalAlignment="Center" NavigateUri="{Binding Path=EmpID,
Converter={StaticResource NavigatePropertyUriConverter}, ConverterParameter=EmpView}"
Content= "{Binding Path=EmpID}" >
</HyperlinkButton>
<!--<HyperlinkButton NavigateUri= "{ Binding Converter={StaticResource navigateConv}, ConverterParameter=/Property/IssuesView?}" VerticalAlignment="Center"
Content="{Binding Path=PropertyId}"
HorizontalAlignment="Right" Margin="5"/>-->
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<!--<sdk:DataGridTextColumn Header="Property #" IsReadOnly="True" Binding="{Binding Path=PropertyId}"/>-->
<sdk:DataGridTextColumn Header="Address" IsReadOnly="True" Binding="{Binding Path=Address}"/>
<sdk:DataGridTextColumn Header="Category" IsReadOnly="True" Binding="{Binding Path=CategoryName}"/>
<sdk:DataGridTextColumn Header="Phone" IsReadOnly="True" Binding="{Binding Path=UnitId}" Visibility="Collapsed"/>
<!--<sdk:DataGridTextColumn Header="Notes" Binding="{Binding Comments}" IsReadOnly="False" />-->
<sdk:DataGridTemplateColumn x:Name="Notes1" Header="Notes">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock MaxWidth="200" TextAlignment="Left" TextWrapping= "Wrap" Text="{Binding Path=Comments, Mode=OneWay}" Width="200" />
<HyperlinkButton Name="btnEllipsis" Visibility="{Binding EllipsisVisibility,Source={StaticResource ViewModel}}" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="15" Content="..." ToolTipService.ToolTip="Click For More" Command="{Binding NotesCommand,Source={StaticResource ViewModel}}" CommandParameter="{Binding}" >
</HyperlinkButton>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid>
and associated property in viewmodel as below
strong text
string _ellipsisVisibility;
public string EllipsisVisibility
{
get { return _ellipsisVisibility; }
set
{
if (_ellipsisVisibility != value)
{
_ellipsisVisibility = value;
RaisePropertyChanged("EllipsisVisibility");
}
}
}
and setting it to
EllipsisVisibility="Collapsed";
and
EllipsisVisibility="Visible";
There are two questions
1. It is not working to show or hide column
2. Need to show the hyperlink button in few rows and or hide in few rows based on some condition like Rowdatabound event in asp.net.
How to do can anyone please help???
(1) DataGrid column visibility is, unfortunately, not a dependency property. This means it can't engage in databinding. Some work-arounds to this involve subclassing the column type you're interested in.
(2) To show/hide a particular control, based on the data for that row, I would use a converter. Or create a new property on that entity type to directly bind to.

Add Row to DataGrid if ItemSource Binding returns no data

is there any simple solution to this problem..first i thought i can create an empty ObservableCollection and writte:
ObservableCollection<PersonDetailsView> newOCollection= new ObservableCollection<PersonDetailsView>();
myDataGrid.ItemsSource=newOCollection.ToArray();
and it works..i get an empty row..but the problem is that i loose the other binding..is there any way to Bind to newOCollection only if my {Binding Person} (see the code) doesn't return a value
<DataGrid CanUserAddRows="True" IsReadOnly="False" BorderBrush="#FFCCCCCC"
GridLinesVisibility="All" AutoGenerateColumns="False"
ItemsSource="{Binding Person}" Background="White" Margin="10,45,0,0"
VerticalAlignment="Top" Height="91" HorizontalAlignment="Left"
HeadersVisibility="None" SelectionMode="Single" Name="dtaPersons" Width="415">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Person.Name, Mode=TwoWay}" Width="Auto"/>
<DataGridTextColumn Binding="{Binding Person.Surname, Mode=TwoWay}" Width="*"/>
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate >
<Button Style="{DynamicResource ChromelessButtonStyle}" Content="r" FontFamily="Marlett" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
ObservableCollection<PersonDetailsView> newOCollection= new ObservableCollection<PersonDetailsView>();
if (!myDataGrid.Items.Any())
myDataGrid.ItemsSource=newOCollection.ToArray();

need to select or highlight alike rows in datagrid with RowDetailsTemplate--mvvm

I have datagrid that have rowdetails. My rows can be duplicated. I want to select all rows that are alike. how can I achieve that. I'm using mvvm pattern. I bind the selectedItem to the same property in my view model, but it does not work.
Here's the xaml code:
<DataGrid Margin="0,6,0,12"
BorderBrush="Silver"
SelectionMode="Single"
HeadersVisibility="Column"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserSortColumns="False"
CanUserReorderColumns="False"
VerticalGridLinesBrush="Silver"
HorizontalGridLinesBrush="Silver"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Auto"
RowDetailsVisibilityMode="Visible"
IsSynchronizedWithCurrentItem="{x:Null}"
ItemsSource="{Binding AccessoryWalls}"
Grid.Row="1"
Grid.Column="0"
Name="gAccessories">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID,StringFormat='W{0}'}" FontWeight="Bold" Foreground="Blue" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate >
<DataTemplate>
<Grid >
<DataGrid ItemsSource="{Binding Accessories}"
SelectedItem="{Binding Path=DataContext.SelectedAccessory, RelativeSource={RelativeSource AncestorType={x:Type UserControl}},Mode=TwoWay}"
CanUserAddRows="False"
HeadersVisibility="Column"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Horizontal"
Width="60"
Binding="{Binding Horizontal, Converter={StaticResource DimensionConverter}}" />
<DataGridTextColumn Header="Vertical"
Width="60"
Binding="{Binding Vertical, Converter={StaticResource DimensionConverter}}" />
<DataGridTextColumn Header="Detail"
IsReadOnly="True"
Binding="{Binding LongName}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate />
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
As you see I bind it to "SelectedAccessory" on VM level and it works. It synchronizes with other controls in the screen, but it does not synchronizes with other rows in the datagrid.
I would like to select all "Overhead Door Opening12" rows when I clicked on one of them.
Thanks in advance.

Resources