how to calculate percentage - c#

I need to calculate percentage in c# and bind it in xaml
in a list of item i need to %the active count by complete count
and bind it in a list called employee list if any one know please help me to figure it out
my calculation
<TextBlock
x:Name="complainceValue"
Grid.Column="6"
Text="{Binding competencylevel}"
FontSize="17"
FontWeight="SemiBold"
public String competencylevel { get; set; }

To calculate a percentage in C# and bind it to an employee list in XAML, you can follow these steps:
First, define a class for an employee object that includes properties for the active count and complete count. For example:
public class Employee
{
public int ActiveCount { get; set; }
public int CompleteCount { get; set; }
}
Next, create a method that calculates the percentage based on the active and complete counts. This method should return a float value representing the percentage:
public float CalculatePercentage(Employee employee)
{
return (float)employee.ActiveCount / employee.CompleteCount * 100;
}
Create a list of employee objects and populate it with data.
List<Employee> employees = new List<Employee>
{
new Employee { ActiveCount = 10, CompleteCount = 20 },
new Employee { ActiveCount = 5, CompleteCount = 10 },
new Employee { ActiveCount = 3, CompleteCount = 6 }
};
In your XAML file, define a ListView or other control to display the employee list. Bind the ItemsSource property to the list of employees and define a DataTemplate to specify how each employee should be displayed.
<ListView ItemsSource="{Binding Employees}">
<ListView.ItemTemplate>
This is the basic structure for calculating and displaying percentages for a list of employees in C# and XAML. To complete the implementation, you can add a TextBlock or other control to the DataTemplate to display the percentage value for each employee.

Related

Representing the first element of a list of list of list in DataGrid XAML

I'm writing a C# WPF application where the user can barcode samples in a test rack into the app.
A rack is made up of rows. Each row contains a number of samples.
Each sample can have a list of sample details (identifier and datetime for every time the user makes a change).
Here is a picture to better visualise it: Picture of Rack
I want to represent this in a DataGrid where the user can edit each sample in the grid.
I'm finding XAML rather difficult. I've managed to achieve what I want using code-behind (see below), but I would like to do this in XAML. Here is the picture of output.
Is this possible?
Thank you
Additional Information:
The number of columns and rows are user defined and will vary between racks
Row headers are bound to the RackPosition property of the Row Class
Column headers are bound to the ColumnPosition of the Sample class
The text inside the DataGridCell is bound to History[0].Identifier
Caliburn Micro will be used to handle the updating of samples by the user
My Code:
Classes:
public class Rack
{
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public List<Row> Rows { get; set; } = new List <Row>();
}
public class Row
{
public int RackPosition { get; set; }
public string Name { get; set; }
public List<Sample> Samples { get; set; } = new List <Sample>();
}
public class Sample
{
public int ColumnPosition { get; set; }
public List<SampleDetails> History { get; set; } = new List <SampleDetails>();
}
public class SampleDetails
{
public string Identifier { get; set; }
public DateTime TimeStamp { get; set; }
}
Datagrid:
<DataGrid x:Name="MainDG" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.RowHeaderStyle>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Content" Value="{Binding RackPosition}"/>
</Style>
</DataGrid.RowHeaderStyle>
</DataGrid>
Code Behind:
public Rack CurrentRack { get; set; }
public MainWindow()
{
InitializeComponent();
SetupDataGrid();
}
//Gets a dummy rack
public Rack GetExampleRack()
{
Rack rack = new Rack();
for (int i = 0; i < 4; i++)
{
Row row = new Row();
row.Samples = new List<Sample>();
row.RackPosition = i;
for (int j = 0; j < 5; j++)
{
row.Samples.Add(new Sample { ColumnPosition = j });
}
rack.Rows.Add(row);
}
SampleDetails testSample1 = new SampleDetails { Identifier = "Test ID 1", TimeStamp = DateTime.Now };
SampleDetails testSample2 = new SampleDetails { Identifier = "Test ID 2", TimeStamp = DateTime.Now };
rack.Rows[0].Samples[0].History.Add(testSample1);
rack.Rows[1].Samples[3].History.Add(testSample2);
return rack;
}
private void SetupDataGrid()
{
MainDG.Columns.Clear();
CurrentRack = GetExampleRack();
foreach (var sample in CurrentRack.Rows[0].Samples)
{
var sampleIndex = CurrentRack.Rows[0].Samples.IndexOf(sample);
DataGridTemplateColumn col = new DataGridTemplateColumn();
col.Header = sampleIndex;
FrameworkElementFactory textBox = new FrameworkElementFactory(typeof(TextBox));
var binding = new Binding();
binding.BindingGroupName = ".";
binding.Path = new PropertyPath($"Samples[{sampleIndex}].History[0].Identifier");
textBox.SetBinding(TextBox.TextProperty, binding);
DataTemplate dt = new DataTemplate { VisualTree = textBox };
dt.Seal();
col.CellTemplate = dt;
MainDG.Columns.Add(col);
}
MainDG.ItemsSource = CurrentRack.Rows;
}
After taking some time to think this one over, I don't think there is any practical way to do this with a DataGrid in XAML. I don't really think DataGrid was designed to handle dynamic columns in the way you need- at least, not automatically via data binding. I also don't know of any other control that would get the job done.
Even accepting that you would have to use some code-behind, I can't pick out any part of your code that could be easily replaced with XAML.
There's no better way to determine the number of columns than by counting Row.Samples- even if you designed some component that could be used in XAML, it would just end up calling the code-behind to do this anyway.
I thought you might at least be able to define the DataTemplate in XAML, but because you need to bind dynamically based on the sampleIndex, you would have to use something like a MultiBinding with a custom IMultiValueConverter. While that would work, I think it ultimately just makes the code more complicated- it's simpler just to leave it as is.
My other thought was to ditch the DataGrid altogether. I considered using an ItemsControl, where the ItemTemplate for the rows contained another ItemsControl for displaying the cells. Then you could bind the main ItemsControl.ItemsSource to Rack.Rows and the row-level ItemsControl.ItemsSource to Row.Samples. This would make all the cells for you automatically, but it gives you other problems:
The column headers would have to be created outside the ItemsControl.
Unless every cell is the same size, they wont line up. You can almost get around this by using a Grid with SharedSizeGroup columns, but Grid doesn't support automatic, dynamic columns from an ItemsSource, so we're back where we started with DataGrid.
There would be no way for the user to drag and resize the columns or rows.
The list goes on, and in solving these problems you would basically end up re-creating all these features that are already present in the DataGrid control.
TL;DR:
I don't think there's a better, XAML-centric, way to do this.

Bind User Input from Text boxes to Collection of Objects via TabControl

I'm relatively new to WPF and the MVVM architecture, as such I'm having issues with this data binding scenario.
I'm currently creating an application that allows users to create new People via a TabControl. When a user creates a new tab, it auto-populates with custom data fields such as First Name, Last Name, Age, etc. I then need to take this information, insert it into an ObservableCollection and use it to populate a WPF report (which I'm not having any issues with). I'm using a tab control so the user can go back and forth and edit the data as needed.
My issues is that only the first item in the tab control actually populates into the ObservableCollection. I have a button that creates a new tab, populates the content with a UserControl. I used the SelectedPerson so that I can go back in the list and access the Person that corresponds with the TabIndex that's currently being viewed so I can change/add/update the string information.
Here is my XAML code:
<TextBox ... Text="{Binding SelectedPerson.FirstName}"/>
<TabControl ... SelectedIndex="{Binding PersonIndex} ... />
My Caregiver class is as follows:
public class Person{
public string FirstName { get; set; }
public string LastName { get; set; }
}
And my C# code looks like:
private int _PersonIndex;
private Person _SelectedPerson;
private ObservableCollection<Person> Persons = new ObservableCollection<Persons>();
public void AddPerson (Person p){
SelectedPerson = p;
Persons.Add(p);
PersonIndex = Persons.Count - 1;
}
public Person SelectedPerson {
get {
return _SelectedPerson;
}
set {
_SelectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
public int PersonIndex{
get {
return _PersonIndex;
}
set {
SelectedPerson = Persons[value];
OnPropertyChanged("PersonIndex");
}
}
Any help would be greatly appreciated!!

Add Tag to ComboBox Items From Model

I have a TypeOfContact model that is made up of an ID, and Text. For example, one type would be Telephone and the ID would be 1. Another type would be Email and the ID 2.
What I would like to do is add the text of the TypeOfContact as an item and the ID as a tag. I imagine it would look something like this, however this isn't working;
contactTypeComboBox.Items.Clear();
foreach (TypeOfContact c in ContactTypes)
{
contactTypeComboBox.Items.Add(c.ContactTypeText);
foreach (ComboBoxItem item in contactTypeComboBox.Items)
{
item.Tag = c.ContactTypeID;
}
}
The reason I want to do this is that when someone selects one of the ComboBox items I want to store the text and the ID. I could do this all through XAML but ContactTypes is a list that is populated by the user, so I cannot hard code the values into the ComboBox as maintaining it and adding new TypesOfContact would be difficult.
I fixed this issue myself by first adding;
DisplayMemberPath="ContactTypeText" SelectedValuePath="ContactTypeID"
to the XAML of the ComboBox then accessing the ID like;
contactTypeComboBox.SelectedValue
In your situation i would bind the list of your TypeOfContacts as ItemsSource to the ComboBox. After that you could set the tag, but i think you don't will need it, because when you also bind the SelectedItem you got back the whole item (ID, type, ...) and can work with it in other parts of your code.
Example for simplifying without a ViewModel (but you should use one):
Codebehind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
FillListWithSomeExamples();
}
private void FillListWithSomeExamples()
{
TypesOfContacts.Add(new TypesOfContact {Id = 1, Type = "Email"});
TypesOfContacts.Add(new TypesOfContact { Id = 2, Type = "Telephone" });
}
public TypesOfContact SelectedTypesOfContact { get; set; }
public ObservableCollection<TypesOfContact> TypesOfContacts { get; set; } = new ObservableCollection<TypesOfContact>();
}
TheTestmodel:
public class TypesOfContact
{
public int Id { get; set; }
public string Type { get; set; }
}
XAML
<Grid>
<ComboBox ItemsSource="{Binding TypesOfContacts}" SelectedItem="{Binding SelectedTypesOfContact}" DisplayMemberPath="Type"/>
</Grid>
Now you can read the selected item in any other method of the MainWindow by looking at SelectedTypesOfContact.

Binding Data to Data Grid

I currently have a URL request the brings back XML data. I store that data in a document that is read and finds the information between certain attributes, and assigns those values to the my assigned variables. my wpf DataGrid is called Movie_DataGrid. Any help would be great on how to get this data to the DataGrid.
-- EDIT --
I updated my code with a new way i am trying to get my results. When stepping through each step of the code, the XML is storing fine, and all tag attributes between the Retrivalinfo class and the Retrievalinfo convertedMovie = new Retrievalinfo() are the same, but application errors out at this method.
My new issue is, the values within the attributes is not being grabbed and stored. I have also put a sample of what XML I would get back.
<root response="True">
<movie title="Up in the Air" year="2009" rated="R" released="23 Dec 2009" runtime="109
min" genre="Drama, Romance" director="Jason Reitman" writer="Walter Kirn (novel), Jason
Reitman (screenplay), Sheldon Turner (screenplay)" actors="George Clooney, Vera Farmiga,
Anna Kendrick, Jason Bateman" plot="With a job that has him traveling around the country
firing people, Ryan Bingham leads an empty life out of a suitcase, until his company
does the unexpected: ground him." language="English" country="USA" awards="Nominated for
6 Oscars. Another 64 wins & 66 nominations."poster="http://ia.mediaimdb.com/images/M/MV5BMTI3MzYxMTA4NF5BMl5BanBnXkFtZTcwMD
E4ODg3Mg##._V1_SX300.jpg" metascore="83" imdbRating="7.5" imdbVotes="215,961" imdbID="tt1193138" type="movie"/>
</root>
// This action will seach the IMDb API for the associated infromation for the IMDBID that is tagged with the title you chose in the ListBox.
private void Movie_List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ // Grabs the IMDBID associated to the movie title selected to be used with the second API request.
var p = Movie_List.SelectedIndex;
string titleID = structholder[p].IMDBID;
// Prepares 2nd API URL request to get data for chosen title.
// Creates a XML Document to store the xml data that was sent back by the API.
XmlDocument doc = new XmlDocument();
doc.Load("http://www.omdbapi.com/?i=" + titleID + "&r=XML");
// Creates a XML Noedlist to store the values that are going to be associated with the given attribute tag.
XmlNodeList movieList = doc.GetElementsByTagName("movie");
var movie = movieList.Item(0);
Retrievalinfo convertedMovie = new Retrievalinfo()
{
title = movie.Attributes["title"].ToString(),
actors = movie.Attributes["actors"].ToString().Split(',').ToList(),
genre = movie.Attributes["genre"].ToString(),
rated = movie.Attributes["rated"].ToString(),
imdbRating = movie.Attributes["imbdRating"].ToString(),
released = movie.Attributes["released"].ToString(),
runtime = movie.Attributes["runtime"].ToString(),
};
List<Retrievalinfo> gridInfo = new List<Retrievalinfo>();
Movie_DataGrid.ItemsSource = gridInfo;
Here is the class where each variable is stored that I want to display in the DataGrid.
namespace WpfApplication3
{
public class Retrievalinfo
{
public Retrievalinfo()
{
actors = new List<string>();
}
//Creating a list of info objects that will store all returned data for selected title.
public string title;
public List<string> actors;
public string genre;
public string rated;
public string imdbRating;
public string released;
public string runtime;
}
}
I though of writing a lengthy aswer but instead, here's a quick sample for you that you can use as reference and figure out the details yourself. MVVM not included :D
Hope it helps.
Codebehind
namespace MyMovies
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Movies = new ObservableCollection<Movie>()
{
new Movie("Lock, Stock and Two Smoking Barrels", 4),
new Movie("Life of Brian", 5),
};
var addMovieCommand = new RoutedUICommand();
CommandManager.RegisterClassCommandBinding(typeof(Window),
new CommandBinding(
addMovieCommand,
(sender, args) => AddMovie(),
(sender, args) => args.CanExecute = true));
AddMovieCommand = addMovieCommand;
}
public ObservableCollection<Movie> Movies { get; set; }
public ICommand AddMovieCommand { get; set; }
private void AddMovie()
{
Movies.Add(new Movie(Guid.NewGuid().ToString(), 3));
}
}
public class Movie
{
public Movie(string name, int stars)
{
Name = name;
Stars = stars;
}
public string Name { get; set; }
public int Stars { get; set; }
}
}
XAML
<Window x:Class="MyMovies.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<DataGrid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Movies}">
</DataGrid>
<Button Content="Add movie" Command="{Binding AddMovieCommand}" />
</StackPanel>
</Grid>
</Window>
Which gives you
If I am understanding your question correctly, you need a few pieces:
An ObservableCollection<RetrievalInfo> in your view model to store the retrieved data
A Datagrid (or perhaps a grid view) in your XAML that has its item source bound to the above property
Columns in the above control to represent each of your data pieces.
The retrieval code should modify the observable collection so they appear on your UI
I would be happy to provide samples for any or all of those pieces that you aren't sure how to implement.
You can read the xml to List of object using the code snippet provided in the following Blog
Blog Link:
http://danielwylie.me/blog/2010/04/c-convert-xml-to-an-object-or-list-of-an-object
You can assign the ItemSource of dataGrid by using the following code snippet
Movie_DataGrid.ItemsSource = list;
//here list object from public static List<T> XmlToObjectList<T>(string xml, string nodePath) method

HierarchicalDataTemplate Distinct leaves

I have a set of data that is structured like this:
ItemA.GroupA
ItemB.GroupA
ItemC.GroupB
ItemD.GroupC
I need to present the data in a WPF Tree View like this:
GroupA
--- ItemA
--- ItemB
GroupB
--- ItemC
GroupC
--- ItemD
What XAML can I use to group the leaves by distinct value? For instance, there could be multple items in the collection which are GroupA.ItemA, however, I only want to present the node and leaf once.
I disagree with itowlson here. This isn't a hairy problem and HierarchicalDataTemplate was made for this kind of thing. Before you go haphazardly diving into patterns and view-models and other unnecessary obfuscation, consider that your problem can be solved with two classes and a single Linq GroupBy statement.
Here are your classes:
public class GroupItem
{
public string Name
{
get;
private set;
}
public string Group
{
get;
private set;
}
public GroupItem(string name, string group)
{
Name = name;
Group = group;
}
}
public class Group
{
public IEnumerable<GroupItem> Children
{
get;
set;
}
public string Name
{
get;
private set;
}
public Group(string name)
{
Name = name;
}
}
So far, so good. You've got two straightforward classes to hold all the necessary data. Names and Groups are stored as strings. A Group has a collection of GroupItem. Now for the code in your Window:
public partial class DistinctLeaves : Window
{
public ObservableCollection<GroupItem> Items
{
get;
set;
}
public IEnumerable<Group> Groups
{
get;
set;
}
public DistinctLeaves()
{
Items = new ObservableCollection<GroupItem>();
Items.Add(new GroupItem("Item A", "Group A"));
Items.Add(new GroupItem("Item B", "Group A"));
Items.Add(new GroupItem("Item C", "Group B"));
Items.Add(new GroupItem("Item D", "Group C"));
Groups = Items.
GroupBy(i => i.Group).
Select(g => new Group(g.Key) { Children = g });
InitializeComponent();
}
}
Once again, this is all boilerplate except the group-by line. That statement merits further investigation. This will group your items collection according to their Group property. After the items are in groups, you then create a new instance of the Group class. Pass in the group's name property (which is the key), and set the children to the group itself, and ta-da!
Finally, here is the XAML for the Window, which uses the HierarchicalDataTemplate:
<Window x:Class="TestWpfApplication.DistinctLeaves"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DistinctLeaves" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TreeView ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
And here is the result:
alt text http://img339.imageshack.us/img339/8555/distinctleaves.jpg
You're not going to be able to do that in XAML, at least not in any natural way. A better approach is to introduce a view model -- a class that represents your data in a view-friendly manner so that you can keep your XAML simple and natural.
Thus, in your case, you would have a class that wraps your ItemX collection, and exposes the groups and their distinct members:
public class MyItemsViewModel
{
public IList<MyGroupViewModel> Groups { get; }
}
public class MyGroupViewModel
{
public string GroupName { get; }
public IList<MyItem> DistinctItems { get; }
}
Your HierarchicalDataTemplate will then fall out almost automatically. As a further benefit, because your view model classes are just data objects, you can put them under automated test, whereas complex XAML requires manual testing.

Categories

Resources