ListView with Dictionary - c#

Hello I'm looking for a way to use listview with Dictionary.
public class ServiceDataObject : IEquatable<ServiceDataObject>
{
public int ServiceID { get; set; }
public string ServiceName { get; set; }
public bool Status { get; set; }
public string ReccomendedStatus { get; set; }
public string WhoMade { get; set; }
public bool Equals(ServiceDataObject other)
{
if (other == null) return false;
return (this.ServiceID.Equals(other.ServiceID));
}
}
public static Dictionary<int, ServiceDataObject> ServiceData = new Dictionary<int, ServiceDataObject>();
This is how my dictionary looks like.
lvUsers.ItemsSource = Order_CONTROLS.ServiceData;
This is how I assign data to listview
And lvUsers listview:
<ListView Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Status}" GroupName="{Binding ServiceName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<DataTemplate.Resources>
<local:InvertBooleanConverter x:Key="InvertBooleanConverter" />
</DataTemplate.Resources>
<RadioButton IsChecked="{Binding Status, Converter={StaticResource InvertBooleanConverter}}" GroupName="{Binding ServiceName}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Reccomendation" Width="120" DisplayMemberBinding="{Binding ReccomendedStatus}" />
<GridViewColumn Header="Description" Width="50" DisplayMemberBinding="{Binding ServiceName}" />
</GridView>
</ListView.View>
Problem is that it does not print data to items only correct, only number of rows are correct, but no data output, can anyone tell what I did wrong and if possible without using LIST(T)?

The solution is to set Values Collection to ItemsSource of the ListView:
lvUsers.ItemsSource = Order_CONTROLS.ServiceData.Values;
Remember also that Dictionary isn't Observable -> INotifyCollectionChanged & INotifyPropertyChanged interfaces aren't implemented.
So if you add a new element to the dictionary, your view will not see this change.

Related

WPF ListView doesn't work

I have been experiencing problems with WPF ListView (using elements binding), as I tried to initialize it by injecting ItemsSource the list of Disks, and got no visual feedback from the element. I wrote my code using the example supplied here.
Here are the relevant code parts:
Setting the ListView
private void viewDisk_Click(object sender, RoutedEventArgs e)
{
List<DiskDetails> data = new List<DiskDetails>();
foreach(Disk disk in disks)
data.Add(new DiskDetails(disk.GetVolumeHeader().DiskName, disk.GetVolumeHeader().DiskOwner,disk.GetVolumeHeader().ProdDate));
disksList.ItemsSource = data;
}
DiskDetails Class
public class DiskDetails
{
public string diskName { get; set; }
public string diskOwner { get; set; }
public string cDate { get; set; }
public DiskDetails(string dN, string dO,string cD)
{
diskName = dN;
diskOwner = dO;
cDate = cD;
}
}
WPF ListView
<Grid Grid.Column="0">
<ListView x:Name="disksList" VerticalAlignment="Top" Height="250" SelectionChanged="disksList_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Disk Name" Width="108" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Disk Owner" Width="108" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Creation Date" Width="108" DisplayMemberBinding="{Binding Mail}" />
</GridView>
</ListView.View>
</ListView>
<Button x:Name="viewDisk" Content="View Disk" Width="90" Height="40" VerticalAlignment="Bottom" Margin="0,0,0,15" Click="viewDisk_Click"/>
</Grid>
Thanks.
Looks like your DisplayMemberBinding wasn't changed from the example code. Try changing the bindings to match the properties of DiskDetails. E.g. DisplayMemberBinding="{Binding Name}" should change to DisplayMemberBinding="{Binding diskName}"

Bind Combox inside a ListView

I have created a ListView with a ComboBox
<ListView x:Name="lstvAttendance" Margin="0,53,0,10">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="0" DisplayMemberBinding="{Binding Path=Id}"/>
<GridViewColumn Header="Emp Code" Width="100" DisplayMemberBinding="{Binding Path=emp_id}"/>
<GridViewColumn Header="Employee Name" Width="160" DisplayMemberBinding="{Binding Path=name}"/>
<GridViewColumn Header="Status" Width="90">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmbStatus" Width="75" Text="{Binding Path=status}" SelectedItem="{Binding Path=status}">
<ComboBoxItem Content="P"/>
<ComboBoxItem Content="A"/>
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Date" Width="135">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DatePicker x:Name="dtpDate" Width="120" Text="{Binding attendance_date}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Reg Date" Width="140" DisplayMemberBinding="{Binding Path=reg_date}"/>
<GridViewColumn Header="Last Update" Width="140" DisplayMemberBinding="{Binding Path=last_update}"/>
<GridViewColumn Header="Delete" Width="70">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnRemove" Content="Remove" Width="60" BorderThickness="0" CommandParameter="{Binding}" HorizontalContentAlignment="Right" Style="{StaticResource DelImg}" Cursor="Hand" Foreground="Blue"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I need to Bind this ComboBox(ComboBox has either P or A).For Binding these ListView from DataBase I created a class Attendance.
public class Attendance
{
public string Id { get; set; }
public string emp_id { get; set; }
public string name { get; set; }
public string status { get; set; } //Either P or A
public string attendance_date { get; set; }
public string reg_date { get; set; }
public string last_update { get; set; }
}
And then:
try
{
using (SqlConnection con = new SqlConnection(DBCon.conStr))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(AppConstraints.LIST_VIEW_ATTENDANCE))
{
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
lstvAttendance.Items.Add(new Attendance()
{
Id = dr["Id"].ToString(),
emp_id = dr["emp_id"].ToString(),
name = dr["name"].ToString(),
attendance_datedr["attendance_date"].ToString(),
status = dr["status"].ToString(),
reg_date = dr["reg_date"].ToString(),
last_update = dr["last_update"].ToString()
});
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
My code works for other fields in ListView. But ComboBox value not select. I need help to select ComboBox value with respect to Database value.
Firstly:Create a List of Attendance instead of adding items to lstvAttendance and then set the lstvAttendance's ItemsSource like this:
List<Attendance> lst = new List<Attendance>();
try
{
....
....
while (dr.Read())
{
lst.Add(new Attendance()
{
....
}
}
...
...
lstvAttendance.ItemsSource = lst;
}
catch
{
....
}
Secondly: You missed the ItemsSource property of your ComboBox it should be like this:
<ComboBox x:Name="cmbStatus" Width="75" DisplayMemberPath="status"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=ItemsSource}"
SelectedValuePath="status" SelectedValue="{Binding Path=status}">
</ComboBox>
You should use SelectedValuePath binding then bind to the SelectedValue=status property of viewModel.
Binding to SelectedItem will always contain the actually selected item ( ComboBoxItem) not the actual value.
<ComboBox x:Name="cmbStatus" Width="75" SelectedValuePath="{Binding Path=Content}" SelectedValue="{Binding Path=status}">
<ComboBoxItem Content="P"/>
<ComboBoxItem Content="A"/>
</ComboBox>

WPF ListView Column of Text Some Rows Underlined Some Not

I need to display databound data in a listview such that some of the cells of the same column are underlined while others are not:
How do I create a data template that will display different control types in the same cell? (Visual Studio 2013, .NET 4.5.2)
XAML:
<ListView Grid.Column="3" ItemsSource="{Binding Results.MyItemSource, Mode=OneWay}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="Auto" Header=" " DisplayMemberBinding="{Binding Path=Caption, Mode=OneWay}"/>
<GridViewColumn Width="Auto" Header=" " DisplayMemberBinding="{Binding Path=Value, Mode=OneWay}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
ItemSource:
public List<object> MyItemSource
{
get
{
return new List<object>
{
new CaptionValuePair {Caption = "Caption1", Value = new TextBlock {Text = "Value1"}},
new CaptionValuePair {Caption = "Caption2", Value = new TextBlock {Text = "Value2", TextDecorations = TextDecorations.Underline}}
};
}
}
Bound type:
public class CaptionValuePair
{
public string Caption { get; set; }
public object Value { get; set; }
}
Problem: The StackPanel is just displaying the typename of a textblock.
Instead of a StackPanel, using an ItemsControl and binding its ItemsSource property worked.
XAML:
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Value, Mode=OneWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
Bound type:
public List<UIElement> Value{ get; set; }

Create columns dynamically in a GridView in WPF MVVM

My MVVM WPF application currently has a GridView that binds to a ViewModel property and has the columns defined in the XAML:
<ListView Grid.Row="0" ItemsSource="{Binding GroupedOrders}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Item2, Mode=OneWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Item1.Date, StringFormat={}{0:dd/MM/yyyy}}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Item1.Name}" />
<!-- lots more -->
</GridView>
</ListView.View>
</ListView>
GroupedOrders is an ObservableCollection of a Tuple of two different item types: an "Order" object and a Boolean that controls whether or not, for this particular view, it is "selected".
However, that "selected" property hasn't been modelled well. It's come to light that each Order needs multiple "selected" properties, depending on the number of dates in the order, which can be between one and five.
To model this in the UI, I need to replace that single Checkbox GridViewColumn with a dynamic construct that creates a similar Checkbox GridviewColumn for each date in the order. So GroupedOrders becomes a Tuple <Order, List<bool>> instead, and there will need to be one column for each bool in the List.
At any given instance, the size of that list will be the same for all the Orders in the grid. But if the user loads new data into the grid, the size of the list will change.
However, I cannot see how to do this in MVVM. Existing solutions seem to be for code-behind where the GridView can be grabbed as an object and manipulated on the fly. The only MVVM solution I've seen to this is to use a Converter to building the entire GridView on the fly, which would seem to be massive overkill for this situation, where there are a lot of columns in the GridView but only a small number need to be dynamic.
Is there another way?
Not sure this is what you expect, but this is what I can think of.
View
<ListView ItemsSource="{Binding Orders}">
<ListView.View>
<GridView>
<GridViewColumn Header="State">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding States}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.Resources>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Value}" Content="{Binding Text}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="OrderNo" DisplayMemberBinding="{Binding OrderNo}" />
</GridView>
</ListView.View>
</ListView>
Code Behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Orders.Add(new Order { OrderNo = "Order001" });
Orders.Add(new Order { OrderNo = "Order002" });
Orders.Add(new Order { OrderNo = "Order003" });
}
private readonly ObservableCollection<Order> _orders = new ObservableCollection<Order>();
public ObservableCollection<Order> Orders
{
get { return _orders; }
}
}
public class Order
{
public Order()
{
States.Add(new State { Text = "Is Paid", Value = false });
States.Add(new State { Text = "Is Delivered", Value = false });
}
public string OrderNo { get; set; }
private readonly ObservableCollection<State> _states = new ObservableCollection<State>();
public ObservableCollection<State> States
{
get { return _states; }
}
}
public class State
{
public string Text { get; set; }
public bool Value { get; set; }
}
Result

WPF Listview databinding to generic List, dynamically filled by WCF service

In WPF app I have a WCF service which dynamically fills a generic List object from a backend database.
How in this case (List created in runtime), I could bind List items to a ListView object items?
It is the Data contract for my Web service:
....
[DataContract]
public class MeetList
{
[DataMember]
public string MeetDate;
[DataMember]
public string MeetTime;
[DataMember]
public string MeetDescr;
.....
static internal List<MeetList> LoadMeetings(string dynamicsNavXml)
{
...// Loads XML stream into the WCF type
}
Here in this event handler I read the WCF service and Loop through a List object:
private void AllMeetings()
{
Customer_ServiceClient service = new Customer_ServiceClient();
foreach (MeetList meet in service.ReadMeetList())
{
?????? = meet.MeetDate; // it's here that I bumped into a problem
?????? = meet.MeetTime; //
?????? = meet.MeetDescr;//
}
}
My Listview XAML:
<Grid>
<ListView Height="100" Width="434" Margin="0,22,0,0" Name="lvItems" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="Date" Width="100" HeaderTemplate="{StaticResource DateHeader}" CellTemplate="{DynamicResource DateCell}"/>
<GridViewColumn Header="Time" Width="100" HeaderTemplate="{StaticResource TimeHeader}" CellTemplate="{DynamicResource TimeCell}"/>
<GridViewColumn Header="Description" Width="200" HeaderTemplate="{StaticResource DescriptionHeader}" CellTemplate="{DynamicResource DescriptionCell}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
And data templates for this ListView:
<Window.Resources>
<DataTemplate x:Key="DateHeader">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="10,0,0,0" Text="Date" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DateCell" DataType="Profile">
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<Binding Path="MeetDate" />
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
......
How in this case (List created in runtime), I could bind my generic List items to a ListView object items?
I tried to use lvItems.ItemsSource = profiles; , but it doesn't work in my event handler
List doesn't have behaviour to notify that items count is changed. You should use a list with support INotifyCollectionChanged.. for example: ObservableCollection<T>. ObservableCollection<T> will inform your lvItems that items count is changed and it will be properly display.
Using intermediate ObservableCollection:
ObservableCollection<Meets> _MeetCollection =
new ObservableCollection<Meets>();
public ObservableCollection<Meets> MeetCollection
{ get { return _MeetCollection; } }
public class Meets
{
public string Date { get; set; }
public string Time { get; set; }
public string Description { get; set; }
}
In the event handler loop we put:
private void AllMeetings()
{
Customer_ServiceClient service = new Customer_ServiceClient();
_MeetCollection.Clear();
foreach (MeetList meet in service.ReadMeetList())
{
_MeetCollection.Add(new Meets
{
Date = meet.MeetDate,
Time = meet.MeetTime,
Description = meet.MeetDescr
});
}
}
And XAML binding is changed to:
<Grid>
<ListView Height="100" Width="434" Margin="0,22,0,0" Name="lvItems" ItemsSource="{Binding MeetCollection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date" Width="100" DisplayMemberBinding="{Binding Date}"/>
<GridViewColumn Header="Time" Width="100" DisplayMemberBinding="{Binding Time}"/>
<GridViewColumn Header="Description" Width="200" DisplayMemberBinding="{Binding Description}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>

Categories