Help binding my silverlight datagrid - c#

I have an entity called Incident, as you can see on the picture, it holds a list with several bugs.
Then I have a datagrid that I connect a list with all my incident to:
List<ExtendedIncident> allIncidents;
myGrid.ItemsSource = allIncidents;
Now I bind some of the values from every incident, like this in the xaml code:
<sdk:DataGrid AutoGenerateColumns="False" Name="grid" SelectionMode="Single" SelectionChanged="grid_SelectionChanged">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Incident">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<HyperlinkButton Content="{Binding CallId}" Click="HyperlinkButton_Click"></HyperlinkButton>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Beskrivnig" Binding="{Binding Description}"></sdk:DataGridTextColumn>
<sdk:DataGridTextColumn Header="Beskrivnig" Binding="{Binding Status}"></sdk:DataGridTextColumn>
</sdk:DataGrid.Columns>
My problem now is that I would like to add some columns that presents some data from the bugs, that are relevant (stored in the list for the incident) in the same row. How can I present data from the list of buggs from the incident?
Would be very thankful for any help

Use RowDetailsTemplate:
<sdk:DataGrid x:Name="dataGrid1" Height="400" IsReadOnly="True" >
<sdk:DataGrid.RowDetailsTemplate>
<DataTemplate>
<sdk:DataGrid ItemsSource={Binding BuggItems}/>
</DataTemplate>
</sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>
Or alternatively a property that aggregates all the items stored in list (below an example if IDs are strings).
public partial class Incident
{
public string IDs
{
get
{
return BuggItems.Aggregate((a,b) => a + "," + b);
}
}
}

Related

Unable to cast object of type ''System.Xml.Linq.XElement' to type 'System.Data.DataRowView'

When I want to get value from DataGrid selected row I had error Unable to cast object of type ''System.Xml.Linq.XElement' to type 'System.Data.DataRowView'.
Date in DataGrid is load from XML file.
C#:
foreach (DataRowView row in dataGrid.SelectedItems)
{
string text = row.Row.ItemArray[0].ToString();
MessageBox.Show(text);
}
XAML:
<DataGrid Name="dataGrid" ItemsSource="{Binding Path=Elements[person]}" AutoGenerateColumns="False" HorizontalAlignment="Left" Height="331" Margin="10,10,0,0" VerticalAlignment="Top" Width="1130" FontSize="14" FontFamily="SimSun">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Element[name].Value}" />
<DataGridTextColumn Header="Date" Binding="{Binding Path=Element[date].Value}" />
</DataGrid.Columns>
</DataGrid>
If you have bound the ItemsSource property to an IEnumerable<XElement>, you won't get any DataRowView objects from the SelectedItems collection. These are XElements and nothing else.
How to get the value of an XElement depends on how your XML data is structured, but the following sample code should give you the idea:
foreach (var row in dataGrid.SelectedItems.OfType<XElement>())
{
XElement nameElement = row.Element("name");
if(nameElement != null)
{
string name = nameElement.Value;
}
}

Data template parameter

There is list with columns to display. I am using ListView with data templates for cells. And my problem is to access both: row and column from template.
Below is demo, xaml:
<ListView x:Name="listView" ItemsSource="{Binding Items}">
<ListView.Resources>
<GridViewColumn x:Key="Column" x:Shared="False">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding WhatHere}" /> <!-- problem here -->
<Run Text="{Binding Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</ListView.Resources>
<ListView.View>
<GridView />
</ListView.View>
</ListView>
and the code:
public partial class MainWindow : Window
{
public List<string> Items { get; } = new List<string> { "1", "2", "3" };
public MainWindow()
{
InitializeComponent();
DataContext = this;
var a = (GridViewColumn)listView.FindResource("Column");
a.Header = "a";
((GridView)listView.View).Columns.Add(a);
var b = (GridViewColumn)listView.FindResource("Column");
b.Header = "b";
((GridView)listView.View).Columns.Add(b);
}
}
will produce
My aim is to have:
a b
a1 b1
a2 b2
a3 b3
Possible? How do I pass column to DataTemplate ? In fact I want to simply know to which column current cell belongs, but please consider following:
This is simplified case.
In reality data templates are more complicated: many elements with bindings, triggers, etc.
In reality column related data are more complicated than just header.
Columns will be generated at runtime with different headers, etc.
Adding columns and setting Header in code-behind is not a problem, DataTemplate is.
I was thinking to use attached property on GridViewColumn, however, it's not parent of cells in the visual tree:
If you want to pass parameter to data template, then you need more MVVM (c) unknown wpf programmer
#mm8, was right, my design lack one more abstraction to hold column information (column name). I've to create column view model (simplified again):
public class ViewModelColumn
{
public string Column { get; }
public ViewModelColumn(string column)
{
Column = column;
}
}
and the code to add column will become something like
var a = new FrameworkElementFactory(typeof(ContentControl));
a.SetValue(ContentControl.ContentProperty, new ViewModelColumn("a"));
((GridView)listView.View).Columns.Add(new GridViewColumn
{
Header = "a",
CellTemplate = new DataTemplate { VisualTree = a }
});
Cell data template is created in code behind. The idea is to supply ContentControl for all cells with column instance bound to Content, then the view needs another data template (this time fully defined in xaml), to know how to visualize it:
<DataTemplate DataType="{x:Type local:ViewModelColumn}">
<TextBlock>
<Run Text="{Binding Column, Mode=OneTime}" />
<Run Text="{Binding DataContext,RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
Such cell DataContext contains column information. To access row (access item from Items), we have to use ListViewItem.DataContext.
Now the view will looks like this:
I am pretty happy about this solution, mostly about combination of things what makes it working, but I guess it could be improved. Hopefully after posting the answer the question become clearer.

How to provide the ID to the Textbox that is inside the Datagrid's datatemplate in wpf in mvvm model, So that I can differentiate the textbox

In My WPF Application I am using MVVM Model. Datagrid Contains Textbox and Label, when provide the input at the run time in the Textbox, dynamically a description will show in label as per the input in the same row.
But the problem is when I provided the input to a textbox, all the textbox with in the datagrid reflect the same input value as their id is not different in grid. how can I solve this problem.
<Grid>
<DataGrid Name="c1DataGrid1" ItemsSource="{Binding CreditInfo}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Credit" Binding="{Binding Path=Credit}"/>
<DataGridTemplateColumn Header="Percentage">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBox Text="{Binding Path=DataContext.CreditPercentage, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<b:Interaction.Triggers>
<b:EventTrigger EventName="LostFocus">
<b:InvokeCommandAction Command="{Binding Path= DataContext.LostFocusCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}">
</b:InvokeCommandAction>
</b:EventTrigger>
</b:Interaction.Triggers>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Description">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Width="440" Text="{Binding PercentageDescription}"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
If I've understood your code correctly you have a grid with 3 columns. The first column contains some value the second column contains textbox where you can insert a value and the third column contains a textbox that calculates percentage of the first column value taking second column value as the percent.
i.e. you have Credit=50 you type 10 into the second column's textbox and you want 5 to appear in the third column.
If that's correct then there is an easier way to achieve what you want.
You create two new properties in the view model for the items bound to your grid. The first property will contain whatever is entered into the textbox of the second column:
private int _creditPercentage;
public int CreditPercentage
{
get { return _creditPercentage; }
set
{
if (value == _creditPercentage)
return;
_creditPercentage= value;
OnPropertyChanged("CreditPercentage");
OnPropertyChanged("PercentageDescription");
}
}
The second property is going to contain the result of the calculation:
public String PercentageDescription
{
get { return Convert.ToString(Math.Round((double)Credit*Percentage/100), CultureInfo.InvariantCulture); }
}
Now you bind the Percentage property to your TextBox in the second column. And PercentageDescription to your third column:
<DataGridTemplateColumn Header="Percentage">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding CreditPercentage}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Description" Binding="{Binding Path=PercentageDescription}"/>
You might also want to implement some input validation in that textbox in the second column to insure that user can only enter digits.
its worked for me by applying the OnPropertyChanged("CreditPercentage"); in the creditinfo property, also define the percentageDescription property in creditmodel.
public ObservableCollection<Credits> CreditInfo
{
get
{
return infos;
}
set
{
infos = value;
OnPropertyChanged("CreditInfo");
OnPropertyChanged("CreditPercentage");
//OnPropertyChanged("PercentageDescription");
}
}public string PercentageDescription
{
get
{
return percentageDescription;
}
set
{
percentageDescription = value;
OnPropertyChanged("PercentageDescription");
}
}

Datagrid ComboBox binding two values

I have a combobox which is populated from a list of names which were obtained from selecting from an Observable collection. However, associated with those names is an ID also in that Observable collection. The goal is when the user selects a new name (Say changes "John" to "Jill") I will be able to obtain the ID, not just the name. The only way I can think of doing this is storing the ID also in the combobox somehow. But I don't know how to do that with binding.
<DataGridTemplateColumn Header="Name ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="namescombo" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Names}"
SelectedItem="{Binding Name, UpdateSourceTrigger=PropertyChanged}" FontSize="12" Background="White" FontFamily="Cambria" BorderBrush="White" BorderThickness="0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
C#
ObservableCollection<Name> Names = new ObservableCollection<Name>();
Name twofields = new Name();
var NamesQuery =
from p in dataEntities.Names
select new { p.Name, p.Id };
foreach (var p in NamesQuery)
{
Names.Add(new Name
{
ID = p.Id,
Name = p.Name
});
}
Names = Names.Select(p => p.Name).Distinct().ToList();
A ComboBox contains properties for both the DisplayMemberPath and the SelectedValuePath, so you could use it to tell the ComboBox to identify items by the "Id" property, but display the "Name" property to the user.
For example,
<DataGridTemplateColumn Header="Name ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Names}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding SelectedId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I would recommend using SelectedValue over SelectedItem because WPF compares SelectedItem by .Equals() which defaults to comparing items by reference, and if your SelectedItem is not the exact same reference as the item in your ItemsSource, it won't get selected.
For example, SelectedItem = new Person(1, "Test"); would probably not set the selected item correctly, while SelectedItem = ItemsSource[0] would since it refers to an item that exists in the ItemsSource.
Also, it frequently makes more sense to store just the Id of the selected item on a row instead of the entire object :)
You can bind directly to Name object collection and set DisplayMemberPath to Name property so that strings are shown on GUI but in essence you have complete object binded to comboBox.
This way you can bind SelectedItem to Name object and can access Id and Name property.
<ComboBox ItemsSource="{Binding Names}" // Collection of name objects.
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedNameObject}"/> // Object of type Name.

how to retrieve All Checked Items from radTreeListView SelectedItems Collection

how do i retrieve all Checked Items from a radTreeListView SelectedItems Collection in c#?
The example below from Retrieve All Checked Items isn't working at all.
foreach ( object checkedItem in radTreeView.CheckedItems )
{
// Get the container(RadTreeViewItem) of the checked item
RadTreeViewItem container = radTreeView.ContainerFromItemRecursive( checkedItem );
// Add your logic for handling the checked item scenario here
}
The XML for the RadTreeListView is
<telerik:RadTreeListView x:Name="radTreeListView" ItemsSource="{Binding Items}"
AutoGenerateColumns="False" Grid.RowSpan="2" SelectionChanged="radTreeListView_SelectionChanged" SelectionMode="Extended" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionChanging="radTreeListView_SelectionChanging" BeginningEdit="radTreeListView_BeginningEdit">
<telerik:RadTreeListView.ChildTableDefinitions>
<telerik:TreeListViewTableDefinition ItemsSource="{Binding Items}" />
</telerik:RadTreeListView.ChildTableDefinitions>
<telerik:RadTreeListView.Columns>
<telerik:GridViewSelectColumn/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" Header="Name" />
</telerik:RadTreeListView.Columns>
</telerik:RadTreeListView>
SelectedItems is the key!
I prepared SampleData as described here and capture checked items with following code.
System.Collections.ObjectModel.ObservableCollection<object> selected_items = radTreeListView.SelectedItems;
foreach (object item in selected_items)
{
WarehouseItem warehouseitem = (WarehouseItem)item;
MessageBox.Show(warehouseitem.Name);
}

Categories

Resources