WPF ListView group and sort - c#

I'm trying to group items on my list and sort them from oldest to newest. Grouping works perfect, it just doesn't want to inverse this list.
WPF Code:
<ListView x:Name="lst_orders" Margin="5" GridViewColumnHeader.Click="results_Click">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="IsSelected" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button x:Name="goto_parts" Content="Show parts" Width="AUTO" Padding="2" Margin="2" Background="#FF179917" Click="goto_parts_Click"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Order ID" Width="100" DisplayMemberBinding="{Binding fullOrderId}" />
<GridViewColumn Header="Job Status" Width="100" DisplayMemberBinding="{Binding status}" />
<GridViewColumn Header="Order Type" Width="150" DisplayMemberBinding="{Binding orderType}" />
<GridViewColumn Header="Customer Notes" Width="250" DisplayMemberBinding="{Binding notes}" />
<GridViewColumn Header="Admin Notes" Width="250" DisplayMemberBinding="{Binding adminNotes}" />
<GridViewColumn Header="Production Notes" Width="100" DisplayMemberBinding="{Binding production_notes}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="Gray">
<TextBlock Text="Days: " FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text=" Systems: " FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding ItemCount}" FontSize="18" FontWeight="Bold"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
C# Code:
ICollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lst_orders.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("daysOld");
view.GroupDescriptions.Add(groupDescription);
view.SortDescriptions.Add(new SortDescription("daysOld", ListSortDirection.Descending));
lst_orders.ItemsSource = view;
daysOld is a property that calculates difference between today's date and order date, works perfect, but I want to see it from the highest number to the lowest. Picture shows what I get, and I want to reverse it.

Your code is correct.I've made a test. It is possible to see in view:
C#:
List<SomeClass> list = new List<SomeClass>();
Random rnd = new Random();
for (int i = 0; i < 10; i++)
{
list.Add(new SomeClass() { DaysOld = DateTime.Now.Add(new TimeSpan(0, rnd.Next(25), 0))});
}
ICollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(list);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("daysOld");
view.GroupDescriptions.Add(groupDescription);
view.SortDescriptions.Add(new SortDescription("DaysOld", ListSortDirection.Descending));
listBox.ItemsSource = view;
listBox.DisplayMemberPath = "DaysOld";
XAML:
<ListBox Name="listBox"/>
Model:
public class SomeClass
{
public DateTime DaysOld { get; set; }
}
Image:

Related

ListView grouping - missing text (WPF, c#, XAML)

I'm trying display ListView grouping. I did as below:
ListView.xaml.cs
ListViewModel lvm = new ListViewModel();
lvUsers3.ItemsSource = lvm.getData();
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lvUsers3.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Type");
view.GroupDescriptions.Add(groupDescription);
ListView.xaml
<ListView Name="lvUsers3" Margin="0,197,94,0" ItemsSource="{Binding tvq}">
<ListView.View>
<GridView>
<GridViewColumn Header="FirstName" Width="100" DisplayMemberBinding="{Binding FirstName}" />
<GridViewColumn Header="LastName" Width="100" DisplayMemberBinding="{Binding LastName}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" FontSize="14" FontStyle="Normal" Text="{Binding Type}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
ListViewModel.cs
namespace LayoutMVVM.ViewModels
{
public class ListViewModel
{
public List<test_view> getData()
{
testViewClassDataContext tv = new testViewClassDataContext();
List<test_view> tvq = (from tt in tv.test_views
select tt).ToList();
return tvq;
}
}
}
On result I see that is grouped but the "type" value is missing (like was hidden?)
When you have applied the grouping you have created a group object that contains your sub items and this is what you are binding your group header to
the group object doesn't contain a Type property to bind to
try "{Binding Name}" instead of "{Binding Type}"

how to access specific control in datatemplate generated listbox

So i have dataTemplate generated listbox like this:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Fill="{Binding color}" Height="10" Width="10" Grid.Column="1"/>
<TextBlock Text=" " Grid.Column="2"/>
<TextBlock Text="{Binding ID}" FontSize="10" FontWeight="Bold" Grid.Column="3"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate
and I bind it to ObservableCollection. I need to access specific item in this listbox and change colour of its rectangle element.
I would use a StyleSelector. make a styleselector like this:
ListViewItemStyleSelector.cs
public class ListViewItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item,
DependencyObject container)
{
Style st = new Style();
st.TargetType = typeof(ListViewItem);
Setter backGroundSetter = new Setter();
backGroundSetter.Property = ListViewItem.BackgroundProperty;
ListView listView =
ItemsControl.ItemsControlFromItemContainer(container)
as ListView;
int index =
listView.ItemContainerGenerator.IndexFromContainer(container);
if (index % 2 == 0) <-- here your own criteria
{
backGroundSetter.Value = Brushes.LightBlue;
}
else
{
backGroundSetter.Value = Brushes.Beige;
}
st.Setters.Add(backGroundSetter);
return st;
}
}
use of the styleselector
xaml
<ListView
ItemsSource="{Binding Source={StaticResource EmployeeData},
XPath=Employee}"
ItemContainerStyleSelector="{DynamicResource myStyleSelector}" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding XPath=FirstName}"
Header="First Name" Width="120"/>
<GridViewColumn DisplayMemberBinding="{Binding XPath=LastName}"
Header="Last Name" Width="120"/>
<GridViewColumn DisplayMemberBinding="{Binding XPath=FavoriteCity}"
Header="Favorite City" Width="120"/>
</GridView>
</ListView.View>
</ListView>

WPF ListView Binding showing class namespace

I have a ListView in my XAML defined as
<vm:JobListView x:Name="JobEditor" ItemsSource="{Binding Path=JobListViewSource}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Width="10" HeaderContainerStyle="{DynamicResource FirstColumnGridViewColumnHeader}" CellTemplate="{StaticResource EmptyColumnTemplate}" />
<vm:SortListViewColumn Header="Description" Width="100" SortProperty="Description" SortStyle="JobDataGridViewColumnHeader" CellTemplate="{StaticResource DescriptionColumnTemplate}" />
<vm:SortListViewColumn Header="Staff" Width="100" SortProperty="Staff.FirstName" SortStyle="JobDataGridViewColumnHeader" CellTemplate="{StaticResource StaffColumnTemplate}" />
<vm:SortListViewColumn Header="Client" Width="50" SortProperty="Client.Name" SortStyle="JobDataGridViewColumnHeader" CellTemplate="{StaticResource ClientColumnTemplate}" />
<vm:SortListViewColumn Header="Samples" Width="100" SortProperty="Samples" SortStyle="JobDataGridViewColumnHeader" CellTemplate="{StaticResource SamplesNoColumnTemplate}" />
<vm:SortListViewColumn Header="Entry Date" Width="100" SortProperty="EntryDate" SortStyle="JobDataGridViewColumnHeader" CellTemplate="{StaticResource EntryDateColumnTemplate}" />
<GridViewColumn Width="10" CellTemplate="{StaticResource EmptyColumnTemplate}" />
</GridView>
</ListView.View>
</vm:JobListView>
vm:JobListView is a class that inherits from ListView
The CellTemplates are defined like this:-
<!-- description column -->
<DataTemplate x:Key="DescriptionColumnTemplate">
<TextBox Style="{StaticResource ReadOnlyTextBlockStyle}" Text="{Binding Path=Description}" />
</DataTemplate>
The ItemsSource is bound to a property on my VM defined like this:-
public ICollectionView JobListViewSource
{
get { return Get(() => JobListViewSource); }
set { Set(() => JobListViewSource, value); }
}
and I set the property like this:-
CollectionViewSource source = new CollectionViewSource();
source.Source = this.Jobs;
this.JobListViewSource = source.View;
where Jobs is an ObservableCollection of Job objects
What I get displayed in my grid is just the namespace of the Job object and not the individual properties in each column
What am I doing wrong?
Try using
this.JobListViewSource.SourceCollection=this.Jobs instead of
CollectionViewSource source = new CollectionViewSource();
source.Source = this.Jobs;
this.JobListViewSource = source.View;

Disabling button on a particular row in WPF gridview

This is my code for generating the gridview
User u1 = new User();
User u2 = new User();
for (int i = 0; i < files.Count; i++)
{
u1.Files = files[i];
items.Add(u1);
}
for (int i = 0; i < sharedFiles.Count; i++)
{
u2.Files += sharedFiles[i];
items.Add(u2);
}
gridview1.ItemsSource = items;
}
public class User
{
public string Files { get; set; }
}
This is my xaml page
<ListView.View>
<GridView >
<GridView.Columns>
<GridViewColumn Width="250" DisplayMemberBinding="{Binding Files}" ></GridViewColumn>
<GridViewColumn >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Download" Click="fileDownloadClick" CommandParameter="{Binding Files}"></Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Share" Click="fileShareClick" CommandParameter="{Binding Files}" ></Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
I would like to know if its possible to only allow my Share buttons disabled in my 2nd for loop (u2) while my Share buttons in (u1) is still enabled. Currently both are enabled. I am currently using this to retrieve values for particular role
private void fileShareClick(object sender, RoutedEventArgs e)
{
object share = ((Button)sender).CommandParameter;
}
Create a DataTrigger on the Button which you want. and bind that with property that represent the boolen type value. like IsShareAllowed.
Try some thing like this.
var procs = (from p in System.Diagnostics.Process.GetProcesses()
select new
{
Name = p.ProcessName,
IsShareAllowed = Convert.ToBoolean(r.Next(-1, 1))
}).ToList(); ;
list.ItemsSource = procs;
Xaml
<ListView Name="list" Grid.Row="4">
<ListView.View>
<GridView >
<GridView.Columns>
<GridViewColumn Width="250" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Download" Click="fileDownloadClick" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Share" Click="fileShareClick" >
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding IsShareAllowed}" Value="false">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>

Show data from textboxes into listview in wpf

I have a C# project have :
The XAML Code:
<Window x:Class="Revision.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Patient Information" Height="456.36" Width="935.208">
<Window.Resources>
<Style x:Key="SliderStyle">
<Setter Property="FrameworkElement.Width" Value="100"/>
<Setter Property="RangeBase.Minimum" Value="0"/>
<Setter Property="RangeBase.Maximum" Value="100"/>
<Setter Property="Slider.IsSnapToTickEnabled" Value="true"/>
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center"/>
<Setter Property="RangeBase.Value" Value="0"/>
<Setter Property="Slider.AutoToolTipPlacement" Value="TopLeft"/>
</Style>
</Window.Resources>
<Grid>
<Label Content="First Name" Height="28" HorizontalAlignment="Left" Margin="19,23,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="Last Name" Height="28" HorizontalAlignment="Left" Margin="19,82,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="Address" Height="28" HorizontalAlignment="Left" Margin="20,144,0,0" Name="label3" VerticalAlignment="Top" />
<Label Content="Security Type" Height="28" HorizontalAlignment="Left" Margin="19,203,0,0" Name="label4" VerticalAlignment="Top" />
<TextBox Height="36" HorizontalAlignment="Left" Margin="105,23,0,0" Name="textBox1" VerticalAlignment="Top" Width="197" />
<TextBox Height="36" HorizontalAlignment="Left" Margin="105,82,0,0" Name="textBox2" VerticalAlignment="Top" Width="197" />
<TextBox Height="36" HorizontalAlignment="Left" Margin="105,136,0,0" Name="textBox3" VerticalAlignment="Top" Width="197" />
<ComboBox Height="36" Margin="105,195,625,0" Name="comboBox1" VerticalAlignment="Top">
<ComboBoxItem Content="Private Assurance" Name="PrA"/>
<ComboBoxItem Content="Public Assurance" Name="PA"/>
<ComboBoxItem Content="No Assurance" Name="NA"/>
</ComboBox>
<Button Content="Submit" Height="33" HorizontalAlignment="Left" Margin="147,365,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
<Button Content="Display" Height="33" HorizontalAlignment="Left" Margin="227,365,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
<Label Content="Gender" HorizontalAlignment="Left" Margin="20,255,0,0" VerticalAlignment="Top"/>
<RadioButton x:Name="maleRadio" Content="Male" HorizontalAlignment="Left" Margin="105,266,0,0" VerticalAlignment="Top"/>
<RadioButton x:Name="femaleRadio" Content="Female" HorizontalAlignment="Left" Margin="192,266,0,0" VerticalAlignment="Top"/>
<Slider x:Name="redSlider" Style="{StaticResource SliderStyle}" Value="{Binding Text, ElementName=textBox5}" Margin="74,313,636,56" SmallChange="1" Height="56" Width="Auto" />
<TextBox x:Name="textBox5" Text="{Binding Value, ElementName=redSlider}" Margin="296,313,588,86" SelectionOpacity="1" FontSize="13" />
<Label Content="Age" HorizontalAlignment="Left" Margin="38,313,0,0" VerticalAlignment="Top"/>
<ListView x:Name="ListView1" HorizontalAlignment="Left" Height="375" Margin="344,23,0,0" VerticalAlignment="Top" Width="567">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" Width="100"
DisplayMemberBinding="" />
<GridViewColumn Header="Last Name" Width="80"
DisplayMemberBinding="" />
<GridViewColumn Header="Address" Width="100"
DisplayMemberBinding="" />
<GridViewColumn Header="Security Type" Width="80"
DisplayMemberBinding="" />
<GridViewColumn Header="Gender" Width="100"
DisplayMemberBinding="" />
<GridViewColumn Header="Age" Width="100"
DisplayMemberBinding="" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
and I have a class patient:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Revision
{
class Patient
{
public string firstname { get; set; }
public string lastname { get; set; }
public string Address { get; set; }
public string securityType {get; set;}
public string gender { get; set; }
public string age { get; set; }
public Patient(string fn, string ln, string ad, string st,string ge,string ag)
{
firstname = fn;
lastname = ln;
Address = ad;
securityType = st;
gender = ge;
age = ag;
}
public override string ToString()
{
return string.Format("{0,-10} {1,-10} {2,-10} {3,-10} {4,-10} {5,-10}",
firstname, lastname, Address, securityType, gender,age);
}
}
}
and the main program
public partial class MainWindow : Window
{
// Patient [] patients = new Patient{}
Patient [] patients = new Patient[100];
private List<Patient> books = new List<Patient>();
int i=0;
string g;
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
string x = "";
if (PrA.IsSelected)
{
x = PrA.Content.ToString();
}
else if (PA.IsSelected)
{
x = PA.Content.ToString();
}
else if (NA.IsSelected)
{
x = NA.Content.ToString();
}
if (maleRadio.IsChecked == true)
g = "Male";
if(femaleRadio.IsChecked==true)
g="Female";
patients[i] = new Patient(
textBox1.Text, textBox2.Text, textBox3.Text, g, textBox5.Text, x);
i = i + 1;
// Patient[] patients = {
// new Patient (
// textBox1.Text, textBox2.Text, textBox3.Text, x)};
textBox1.Clear();
textBox2.Clear();
textBox3.Clear();
textBox5.Clear();
}
}
So the question I want to display the data entered in the textboxes,radio button and combo box... in the List view
The normal way of getting your data into the listview would be through databinding. Databinding is the way that WPF uses to transport data between your view and your code.
All wpf controls that can show multiple items, like listview, listbox, combobox etc, has a ItemSource property. By setting this property to an enumerable, the view will display each item in the collection.
By default, it will just render each item as a textblock showing the result of calling ToString() on each object. There are several ways of customizing this. In your case, you have defined columns with a GridView and GridViewColumns. Each GridViewColumn has a DisplayMemberBinding which can be binded to the property you want to display in that column.
So...
I'm not sure how easy it will be for you to use this. As mentioned by others, you really should learn a little bit about binding in wpf, and the Model-View-ViewModel (MVVM) pattern. MVVM really helps keeping the code clean.
Anyways...
Your view could be changed to something like this:
<ListView x:Name="ListView1" HorizontalAlignment="Left" Height="375" Margin="344,23,0,0" VerticalAlignment="Top" Width="567" ItemsSource="{Binding patients}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" Width="100" DisplayMemberBinding="{Binding path=firstname}" />
<GridViewColumn Header="Last Name" Width="80" DisplayMemberBinding="{Binding path=lastname}" />
<GridViewColumn Header="Address" Width="100" DisplayMemberBinding="{Binding path=Address}" />
<GridViewColumn Header="Security Type" Width="80" DisplayMemberBinding="{Binding path=securityType}" />
<GridViewColumn Header="Gender" Width="100" DisplayMemberBinding="{Binding path=gender}" />
<GridViewColumn Header="Age" Width="100" DisplayMemberBinding="{Binding path=age}" />
</GridView>
</ListView.View>
</ListView>
I would change your fixed size array of patients to a ObservableCollection<Patient>. A collection that can grow in size is almost always better than a fixed size one. The ObservableCollection<> has some extra tricks as well. It will notify the view whenever items are added or removed.
Take a look at wpftutorial.net. You will find a nice introduction to binding , MVVM and a lot more.

Categories

Resources