Dynamically creating GridViewItem XAML - c#

I have a list that will not always have the same number of objects in it, could be 1, 10, 15, etc. Right now I am just guessing and placing that guessed amount of GridviewItems in my XAML. I want to dynamically build the GridviewItems based on the amount of objects in my list. I have have this in a loop of course, I am just unsure of how to do this in c#. I will show you the XAML I have right now that is not dynamically creating the GridviewItems.
<Grid Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<controls:PageHeader BackButtonVisibility="Collapsed" Content="News" Frame="{x:Bind Frame}">
<Interactivity:Interaction.Behaviors>
<Behaviors:EllipsisBehavior Visibility="Auto" />
</Interactivity:Interaction.Behaviors>
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<GridView Margin="12,60" ItemsSource="{Binding myList}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Vertical" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="#2A2A2A" Margin="5" Height="200" Width="300">
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</GridView.ItemContainerStyle>
</GridView>
</Grid>
Web Service
[OperationContract]
List<ViewDetails> ViewDetails();
[DataContract]
public class ViewDetails
{
public string TitleView { get; set; }
public string BodyView { get; set; }
public string AuthorView { get; set; }
public ViewDetails() { }
public ViewDetails(string myTitleView, string myBodyView, string myAuthorView)
{
this.TitleView = myTitleView;
this.BodyView = myBodyView;
this.AuthorView = myAuthorView;
}
}
public List<ViewDetails> ViewDetails()
{
List<ViewDetails> details = new List<ViewDetails>();
SqlConnection conn = new SqlConnection(strConnString);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT TOP 2 [My_Title] AS 'Title', [My_Body] AS 'Body', [My_Author] AS 'Author' FROM [My_table] ORDER BY [Date] DESC", conn);
SqlDataReader rdrDetails = cmd.ExecuteReader();
try
{
while (rdrDetails.Read())
{
details.Add(new ViewDetails(rdrDetails.GetSqlString(rdrDetails.GetOrdinal("Title")).ToString(), rdrDetails.GetSqlString(rdrDetails.GetOrdinal("Body")).ToString(), rdrDetails.GetSqlString(rdrDetails.GetOrdinal("Author")).ToString()));
}
}
catch (Exception e)
{
//exception
}
finally
{
conn.Close();
}
return details;
}
Project where I am calling web service
public async void ViewData()
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
string title = string.Empty;
string body = string.Empty;
string author = string.Empty;
var res = await client.ViewDetailsAsync();
for (int i = 0; i < res.Count; i++)
{
myList.Add(new GetDetails(res[i].TitleView, res[i].BodyView, res[i].AuthorView));
}
}
public class GetDetails
{
public string TitleView { get; set; }
public string BodyView { get; set; }
public string AuthorView { get; set; }
public GetDetails() { }
public GetDetails(string titleView, string bodyView, string authorView)
{
this.TitleView = titleView;
this.BodyView = bodyView;
this.AuthorView = authorView;
}
}
What I am looking for is some way to programatically build the GridViewItems... Any suggestions?

Just bind ItemsSource
<GridView Margin="12,60" ItemsSource={Binding ItemsList}>
...
</GridView>
EDIT:
1) You can use DataGrid like this
<DataGrid ItemsSource="{Binding TestDataCollection}">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding TitleView}"/>
<DataGridTextColumn Header="Body" Binding="{Binding BodyView}"/>
<DataGridTextColumn Header="Author" Binding="{Binding AuthorView}"/>
</DataGrid.Columns>
</DataGrid>
2) Or ListView
<ListView ItemsSource="{Binding TestDataCollection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Author" DisplayMemberBinding="{Binding Path=AuthorView}"/>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=TitleView}"/>
</GridView>
</ListView.View>
</ListView>
3) Or ListBox
<ListBox ItemsSource="{Binding TestDataCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding AuthorView}"/>
<TextBlock Text="{Binding TitleView}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

How to Add a Quantity Column on a DataGrid from ListView selection in WPF

I've a ListView whose data I select and send to a DataGrid. I am having trouble with the quantity column of the DataGrid which I would want to calculate how many times a ListView item has been added to the said DataGrid (I'm currently displaying a success message when the same item is selected). I would also want to calculate the price and the quantity and display them on one column named 'price' the DataGrid.
Here is the Datagrid
<ListView x:Name="ItemGridView" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" PreviewMouseDoubleClick="ItemGridView_PreviewMouseDoubleClick">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ItemImage}" Width="225" Height="157" Stretch="UniformToFill" StretchDirection="DownOnly" />
<StackPanel Margin="0,100,0,0">
<Border Margin="-0,-7,0,0" Height="63" Width="225" Background="{x:Null}" BorderBrush="{x:Null}" BorderThickness="0">
<TextBlock Margin="8" FontWeight="Heavy" Foreground="White" FontSize="16" Text="{Binding ItemName}"/>
</Border>
<TextBlock Margin="15,-28,0,0" FontSize="15" Text="{Binding SellingPrice}" Foreground="White"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The DataGrid to which the data is sent looks like this:
<DataGrid x:Name="DGItems" ItemsSource="{Binding}" VerticalAlignment="Top" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="0" MinHeight="350" MaxHeight="350" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" CanUserSortColumns="True" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn MinWidth="3" Header="#" Width="Auto" Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={global:RowToIndexConverter}}" />
<DataGridTextColumn Header="Items" Binding="{Binding ItemName}" />
<DataGridTextColumn Header="Cost" Binding="{Binding SellingPrice}" />
<DataGridTextColumn Header="Qty" />
</DataGrid.Columns>
</DataGrid>
The code behind to send the datan following a ListView double click event is as below:
private void ItemGridView_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var selectedItem = ItemGridView.SelectedItem;
if (!DGItems.Items.Contains(selectedItem))
{
DGItems.Items.Add(selectedItem);
}
else
{
utilityMethods.InformationMessage("Attempted to add item successfully");
}
}
I've included screenshots to preview how the application looks just to put the question in context.
Here's a working sample. I made slight modifications to your xaml and bindings to show how it can be done. Whenever you double-click an item in the ListView, it will update both the Quantity and Total columns in the DataGrid.
MyItem.cs: This is a simple model to replicate your food item
namespace UpdateQuantityColumnTest
{
public class MyItem
{
public string ItemName { get; set; }
public double SellingPrice { get; set; }
}
}
ListViewItemViewModel.cs: This is a view model representation of your MyItem for the ListView
namespace UpdateQuantityColumnTest
{
public class ListViewItemViewModel : ViewModelBase
{
public ListViewItemViewModel(MyItem model)
{
this.Model = model;
}
public MyItem Model { get; private set; }
public string ItemName { get => this.Model.ItemName; set { this.Model.ItemName = value; OnPropertyChanged(); } }
public string SellingPrice { get => this.Model.SellingPrice.ToString("c"); }
}
}
DGItemViewModel: This is a slightly different view model representation of your MyItem for the DataGrid, but includes a Quantity and a TotalPrice
namespace UpdateQuantityColumnTest
{
public class DGItemViewModel : ViewModelBase
{
private int quantity;
public DGItemViewModel(MyItem model)
{
this.Model = model;
this.quantity = 1; // always start at 1
}
public MyItem Model { get; private set; }
public string ItemName { get => this.Model.ItemName; set { this.Model.ItemName = value; OnPropertyChanged(); } }
public string SellingPrice { get => this.Model.SellingPrice.ToString("c"); }
public int Quantity { get => this.quantity; set { this.quantity = value; OnPropertyChanged(); OnPropertyChanged(nameof(TotalPrice)); } }
public string TotalPrice { get => (this.Model.SellingPrice * this.Quantity).ToString("c"); }
}
}
ViewModelBase.cs: This is the base class that simply handles the INotifyPropertyChanged to update the UI whenever one of the property values change in your view model
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace UpdateQuantityColumnTest
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml: I made slight changes, mainly to your bindings so that my sample could work
<Window x:Class="UpdateQuantityColumnTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView x:Name="ItemGridView" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" PreviewMouseDoubleClick="ItemGridView_PreviewMouseDoubleClick">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ItemImage}" Width="225" Height="157" Stretch="UniformToFill" StretchDirection="DownOnly" />
<StackPanel Margin="0,100,0,0">
<Border Margin="-0,-7,0,0" Height="63" Width="225" Background="{x:Null}" BorderBrush="{x:Null}" BorderThickness="0">
<TextBlock Margin="8" FontWeight="Heavy" Foreground="White" FontSize="16" Text="{Binding ItemName}"/>
</Border>
<TextBlock Margin="15,-28,0,0" FontSize="15" Text="{Binding SellingPrice}" Foreground="White"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<DataGrid x:Name="DGItems" ItemsSource="{Binding CheckoutItems}" VerticalAlignment="Top" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="1" MinHeight="350" MaxHeight="350" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" CanUserSortColumns="True" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Items" Binding="{Binding ItemName}" />
<DataGridTextColumn Header="Cost" Binding="{Binding SellingPrice}" />
<DataGridTextColumn Header="Qty" Binding="{Binding Quantity}"/>
<DataGridTextColumn Header="Total" Binding="{Binding TotalPrice}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.cs: The code-behind that does all the work
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace UpdateQuantityColumnTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<ListViewItemViewModel> items;
private ObservableCollection<DGItemViewModel> checkoutItems;
public MainWindow()
{
InitializeComponent();
this.Loaded += OnLoaded;
this.DataContext = this;
}
public ObservableCollection<ListViewItemViewModel> Items
{
get
{
if (this.items == null)
this.items = new ObservableCollection<ListViewItemViewModel>();
return this.items;
}
}
public ObservableCollection<DGItemViewModel> CheckoutItems
{
get
{
if (this.checkoutItems == null)
this.checkoutItems = new ObservableCollection<DGItemViewModel>();
return this.checkoutItems;
}
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Populate with dummy data
this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Beef Steak", SellingPrice = 1000 }));
this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Bacon Brie", SellingPrice = 1200 }));
this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Bread and Sausage", SellingPrice = 700 }));
}
private void ItemGridView_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var selectedItem = ItemGridView.SelectedItem as ListViewItemViewModel;
var checkoutItem = this.CheckoutItems.SingleOrDefault(o => o.ItemName == selectedItem.ItemName);
if (checkoutItem == null)
{
this.CheckoutItems.Add(new DGItemViewModel(selectedItem.Model));
}
else
{
//utilityMethods.InformationMessage("Attempted to add item successfully");
checkoutItem.Quantity++;
}
}
}
}
If the items in the ItemsSource = "{Binding Items}" collection have an INotifyPropertyChanged implementation and notify about the change of their properties, then you can solve this problem with minimal changes.
Add an int Qty property to the element class and change your method:
if (!DGItems.Items.Contains(selectedItem))
{
DGItems.Items.Add(selectedItem);
selectedItem.Qty = 1;
}
else
{
selectedItem.Qty++;
utilityMethods.InformationMessage("Attempted to add item successfully");
}
And add a binding to this property in the column:
<DataGrid.Columns>
<DataGridTextColumn MinWidth="3" Header="#" Width="Auto" Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={global:RowToIndexConverter}}" />
<DataGridTextColumn Header="Items" Binding="{Binding ItemName}" />
<DataGridTextColumn Header="Cost" Binding="{Binding SellingPrice}" />
<DataGridTextColumn Header="Qty" Binding="{Binding Qty}" />
</DataGrid.Columns>

WPF ListView Headers Repositioning

I have a ListView (with an inner ListView) that displays data like this:
I would like to display the inner ListView headers above the grouping like so:
Is it possible to re-position the column headers as shown or simply create some fake headers on the outer ListView?
Here is the XAML code I have so far:
<ListView Name="ListView_GarnishmentCalculations"
ItemsSource="{Binding GarnishedEmployees, UpdateSourceTrigger=PropertyChanged}"
MaxHeight="{Binding ActualHeight,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollContentPresenter}},
Converter={StaticResource MathConverter}, ConverterParameter=x-220}"
Margin="5,20,10,10"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4">
<!-- Required for right justifying text in a TextBlock -->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<!-- Group results and show EmpNo, Name and WorkState -->
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid ShowGridLines="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="175" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Items[0].EmpNo}"
FontWeight="Bold"
Grid.Column="0" />
<TextBlock Text="{Binding Items[0].FullName}"
FontWeight="Bold"
Grid.Column="1" />
<TextBlock Text="{Binding Items[0].WorkState}"
FontWeight="Bold"
Grid.Column="2" />
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<!-- Inner ListView of garnishment details -->
<ListView ItemsSource="{Binding Garnishments}">
<ListView.View>
<GridView>
<!-- CaseID -->
<GridViewColumn Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CaseNumber, Converter={StaticResource StringIsNullOrEmptyConverter}, ConverterParameter='No Case ID'}"
TextAlignment="Left">
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Content=" Case ID" />
</GridViewColumn.Header>
</GridViewColumn>
<!-- Vendor -->
<GridViewColumn Width="150"
DisplayMemberBinding="{Binding Vendor}">
<GridViewColumn.Header>
<GridViewColumnHeader Content=" Vendor" />
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is what I came up with, NOT by my self I used my google fu skills for this.
Credit to this SO post.
So here is what I have for my model:
namespace Model
{
public class Case
{
public int CaseID { get; set; }
public int Vendor { get; set; }
}
}
And now user:
namespace Model
{
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string State { get; set; }
public List<Case> Cases { get; set; }
}
}
Now in my MainViewModel:
using Model;
using System.Collections.Generic;
namespace VM
{
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
Users = new List<User>();
for (int i = 0; i < 20000; i++)
{
Users.Add(new User
{
ID = i,
Name = $"John the {i + 1}",
State = i % 2 == 0 ? "CA" : "IL",
Cases = new List<Case>() { new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 }, new Case { CaseID = (i + 1) * 10, Vendor = ((i + 1) * 10) - 2 } }
});
}
}
private List<User> users;
public List<User> Users
{
get { return users; }
set { users = value; OnPropertyChanged(); }
}
}
}
On to the View:
<Window x:Class="SO_App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:VM;assembly=VM"
xmlns:model="clr-namespace:Model;assembly=Model"
xmlns:local="clr-namespace:SO_App"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<CollectionViewSource Source="{Binding Users}" x:Key="Users"/>
</Window.Resources>
<Grid>
<ListView>
<ListView.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource Users}}"/>
</CompositeCollection>
</ListView.ItemsSource>
<ListView.View>
<GridView>
<GridViewColumn Header="Case ID" Width="100"/>
<GridViewColumn Header="Vendor" Width="100"/>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</DataTemplate.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding ID}" MinWidth="50"/>
<TextBlock Text="{Binding Name}" MinWidth="250" Grid.Column="1"/>
<TextBlock Text="{Binding State}" MinWidth="50" Grid.Column="2"/>
<ListView Grid.Row="1" ItemsSource="{Binding Cases}" Grid.ColumnSpan="3">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding CaseID}" MinWidth="100"/>
<TextBlock Text="{Binding Vendor}" MinWidth="100" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Caveat:
You will need to handle the scroll event on the inner ListView so it doesn't swallow the mouse scroll.
P.S.
this is the BaseViewModel implementation:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace VM
{
public class BaseViewModel : INotifyPropertyChanged
{
#region INPC
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string prop = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
#endregion
}
}
Which then produces this as a result:

How to obtain row index and assign it to observable collection property of datagrid

Basically, I have a DataGrid inside a DataGrid:
<DataGrid ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
AutomationProperties.AutomationId="sCGridSelectedBasketItems"
HeadersVisibility="Row"
Height="{Binding ElementName=itemsgrid,Path=ActualHeight}"
Grid.Row="1"
RowDetailsVisibilityMode="Visible"
CanUserAddRows="false"
VerticalAlignment="Top"
AutoGenerateColumns="False"
SelectedItem="{Binding SelectedBasketItem}"
ItemsSource="{Binding SelectedOrderBasketItems}"
CanUserDeleteRows="True">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
CanUserAddRows="false"
HeadersVisibility="Row"
AutoGenerateColumns="False"
ItemsSource="{Binding SelectedBasketItems}"
SelectedValue="{Binding SelectedBasketItemValue}"
SelectedIndex="{Binding SelectedOrderItemIndex}"
SelectedItem="{Binding SelectedSpecificItemInBasket, Mode=TwoWay}"
SelectionChanged="datagrid_SelectionChanged"
DataGrid.SelectionMode="Single"
Style="{StaticResource GridItemsControlStyle}"
ctrls:DragDrop.DropHandler="{Binding DropHandler}">
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True"
Binding="{Binding Path=ItemName}"
Width="195">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping"
Value="Wrap" />
<!--<Setter Property="TextBlock.TextAlignment"
Value="Center" />-->
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=RulesCount}"
Background="{Binding Path=RulesCount ,Converter={StaticResource ItemColourConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="115">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=LinkedOrderCount}"
Background="{Binding Path=LinkedOrderCount ,Converter={StaticResource ItemColourConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="55">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=SDICount}">
<Label.Background>
<MultiBinding Converter="{StaticResource SdiItemColourConverter}">
<Binding ElementName="SDIMaxCnt"
Path="Value" />
<Binding Path="SDICount" />
</MultiBinding>
</Label.Background>
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
My ObservableCollection has the following fields where I have to bind SelectedItemIndex of each DataGrid row with SelectedOrderItemIndex(which is a property of ObservableCollection class MobileOrderBasketItems.cs):
public int SelectedOrderItemIndex
{
get
{
return selectedOrderItemIndex;
}
set
{
selectedOrderItemIndex = value;
}
}
My Observable collection:
public ObservableCollection<MobileOrderBasketItems> SelectedBasketItems
{
get
{
return _selectedBasketItems ?? (_selectedBasketItems = new ObservableCollection<MobileOrderBasketItems>());
}
set
{
_selectedBasketItems = value;
}
}
My ObservableCollection class definitions:
public class MobileOrderBasketItems
{
private int _sdiMaxCountVal;
private int selectedOrderItemIndex;
public string GrName { get; set; }
public string ItemName { get; set; }
public string RulesCount { get; set; }
public string LinkedOrderCount { get; set; }
public string SDICount { get; set; }
public int SelectedOrderItemIndex
{
get
{
return selectedOrderItemIndex;
}
set
{
selectedOrderItemIndex = value;
}
}
private ObservableCollection<MobileOrderBasketItems> _selectedBasketItems;
public ObservableCollection<MobileOrderBasketItems> SelectedBasketItems
{
get
{
return _selectedBasketItems ?? (_selectedBasketItems = new ObservableCollection<MobileOrderBasketItems>());
}
set
{
_selectedBasketItems = value;
}
}
}
Any help on how to achieve this is much appreciated.

Select text from a list view when that is cliked C# Metro App

I have a list view which I populate it from an API.. I want it fill a text box with the value which is found in the text block when I click..
My Listview...
<ListView Width="300" Height="134" x:Name="lsvObjectives" IsItemClickEnabled="True" SelectionMode="Multiple" ItemsSource="{Binding Source={StaticResource cvsObjectives}}" ItemClick="lsvObjectives_ItemClick">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" HorizontalChildrenAlignment="left"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="-7"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0,0,0,0" HorizontalAlignment="Center" >
<StackPanel Orientation="Horizontal" Width="310" Height="33" Background="#FFE9D5F0" HorizontalAlignment="Left">
<StackPanel Width="270" VerticalAlignment="Center" Margin="10,5,0,0">
<TextBlock Text="{Binding objective}" Style="{StaticResource ContentTextBlockStyle}" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="13"/>
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is how I populate the list:
private async void getObjectives()
{
string getObjectives = baseAddress + "unitPlansDetailsByUnit/1";
var content = await httpClient.GetStringAsync(new Uri(getObjectives));
objectivesHelper data = JsonConvert.DeserializeObject<objectivesHelper>(content);
foreach (var item in data.result)
{
cvsObjectives.Source = data.result;
}
}
My Classes:
public class objectives
{
public int id { get; set; }
public string objective { get; set; }
}
class objectivesHelper
{
public List<objectives> result { get; set; }
}
I am unable to read the value from the text block which is found in my list view..
Someone kindly help me do this..
Any kind of help is appreciated....
You can read the value in your lsvObjectives_ItemClick method by casting the ItemClickEventArgs.ClickedItem to your type objectives.
For example:
private void lsvObjectives_ItemClick(object sender, ItemClickEventArgs e)
{
objectives item = e.ClickedItem as objectives;
var itemText = item.objective;
youtTextBox.Text = item.Description.ToString();
}

How to populate a DataGridComboBoxColumn?

I have a DataGrid, one of the columns is a DataGridComboBoxColumn:
<DataGrid AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTextColumn Header="User Name" Width="Auto" Binding="{Binding UName}"/>
<DataGridComboBoxColumn Header="Country" Width="Auto" ????/>
</DataGrid.Columns>
</DataGrid>
I have a Country class:
public class Country{
public string name {get; set;}
public string des {get; set;}
public Country() {}
public Country(string n, string d) {
this.name = n;
this.des = d;
}
}
they have a name and a description, I want the names(of multiple Country objects) to populate the combo-box(and the des the tooltip of each combo-box option), how do I do that?
Note: later I would like to give the user the ability to add a new Country, so I would like the combo-box to change as well(to include the new Country), meaning the solution needs to allow that.
Note2: I am not using the MVVM pattern. edit: meaning it is not a duplicate.
Solution:
1. XAML:
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTextColumn Header="User UName" Width="Auto" Binding="{Binding UName}"/>
<DataGridComboBoxColumn x:Name="ComboBoxColumn" Header="Country" Width="Auto" DisplayMemberPath="name" SelectedItemBinding="{Binding CountryData}"/>
</DataGrid.Columns>
</DataGrid>
2. Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitData();
ComboBoxColumn.ItemsSource = CountriesCollection;
DataGrid.ItemsSource = UsersCollection;
}
private void InitData()
{
UsersCollection = new ObservableCollection<UserData>(new List<UserData>
{
new UserData
{
UName = "Greg",
},
new UserData
{
UName = "Joe",
},
new UserData
{
UName = "Iv",
}
});
CountriesCollection = new ObservableCollection<Country>(new List<Country>
{
new Country("Ger", "1500"),
new Country("Fra", "1500"),
new Country("Ru", "1500"),
new Country("Bel", "1500"),
});
}
public ObservableCollection<Country> CountriesCollection { get; set; }
public ObservableCollection<UserData> UsersCollection { get; set; }
}
3. User model:
public class UserData
{
public string UName { get; set; }
public object CountryData { get; set; }
}
4. tool tip support: replace a desired combo box column with next xaml code:
<DataGridComboBoxColumn x:Name="ComboBoxColumn" Header="Country" DisplayMemberPath="CountryName"
ItemsSource="{StaticResource CountriesArray}" Width="Auto"
SelectedItemBinding="{Binding CountryData, UpdateSourceTrigger=PropertyChanged}">
<DataGridComboBoxColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip">
<Setter.Value>
<ContentControl Content="{Binding }">
<ContentControl.ContentTemplate>
<DataTemplate DataType="{x:Type soDataGridProjectsHelpAttempt:UserData}">
<DataTemplate.Resources>
<system:String x:Key="NoAnyEntriesKey">
No any entry presented
</system:String>
</DataTemplate.Resources>
<TextBlock Text="{Binding CountryData.Description, FallbackValue={StaticResource NoAnyEntriesKey}}"></TextBlock>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.CellStyle>
</DataGridComboBoxColumn>
and take in account you nedd to extend Country model with description property.
regards,

Categories