Dynamic TabItems c# Wpf - c#

I am new to WPF and I am creating an application which uses the TabControl. I am using a DataTemplateSelector and my datasource is an object I created from XML which have the properties "type" and "categoryID". I select my data template based on the "type" which works fine but I also need to create a tabitem for each categoryID during runtime. My problem is currently it creates a new TabItem for each object. How do I create a new tabitem based on the categoryID and place the dataTemplate on that tab and if the tab have already been created place the DataTemplate on that tab instead of creating a new one.
Thanks in advance!!

I ended up using a CollectionViewSource with grouping and then I set the tabcontrol datacontext to the CollectionViewSource.
private void PopulateTabControl()
{
DataView = (CollectionViewSource)(this.Resources["DataView"]);
AddGrouping();
tabcontrol.DataContext = DataView;
}
private void AddGrouping()
{
PropertyGroupDescription grouping = new PropertyGroupDescription();
grouping.PropertyName = "categoryID";
DataView.GroupDescriptions.Add(grouping);
}

Related

Windows Presentation Foundation How to add items to Listview using code

i want to add Items to my Listview, which i create dynamically using C#.
It looks kinda like this:
System.Windows.Controls.ListView test = new ListView();
test.Margin = new Thickness(28 + i, 23,485 - i, 23);
test.BorderBrush = new SolidColorBrush(Colors.Red);
test.BorderThickness = new Thickness(2);
test.VerticalContentAlignment = VerticalAlignment.Center;
Grid.SetColumn(test,1);
Grid.SetRow(test,1);
Now obviously the Listviews i create are completely empty.
So again my question: Is there any posibility to add items (say from an object) and display them in those Listviews i create here?
Ques : Is there any posibility to add items (say from an object) and display them in those Listviews i create here?
Let's say you get a list of string from an object. Like, objectMain.stringlist where objectMain is your object and stringlist is a property (List<string>) inside your object. Then, you can assign it like, test.ItemsSource = objectMain.stringlist
Using code behind is not recommended. Try using MVVM and create UIElements from the xaml.
I recommand you use MVVM patern to bind a list to ItemsSource in ListView and do that in xaml, but in code it is still available manually.
GridView gv = new GridView();
gv.Columns.Add(new GridViewColumn() { Header = "Something" });
test.View = gv;
test.Items.Add("Data1");

defining custom DataTemplates and assign them to the ListView ItemTemplate

I'm trying to get into Xamarin development and followed Microsofts video tutorial
https://www.youtube.com/watch?v=OPXVqdRXZms&list=PLdo4fOcmZ0oU10SXt2W58pu2L0v2dOW-1&index=9
Currently I would like to populate my ListView with some basic labels. So first the following code works fine for me. I created a custom ViewCell and assign it to the ListView as the ItemTemplate
public class MasterPage : ContentPage
{
public ListView MasterPageNavigationItemsView { get; }
public MasterPage()
{
// ...
MasterPageNavigationItemsView = new ListView()
{
ItemTemplate = new DataTemplate(() => new MasterPageItemViewCell()),
SeparatorVisibility = SeparatorVisibility.None
};
MasterPageNavigationItemsView.SetBinding(ListView.ItemsSourceProperty, nameof(MasterViewModel.MasterPageItemsCollection));
// ...
}
}
internal class MasterPageItemViewCell : ViewCell
{
public MasterPageItemViewCell()
{
Label label = new Label();
label.SetBinding(Label.TextProperty, nameof(MasterPageItem.Title));
View = label;
}
}
I would prefer to create a custom DataTemplate as they did in the video tutorial. I found the code on Github
https://github.com/codemillmatt/xamarin-101/blob/8271814c7ebdd41387e20ed33b3dfbdcd54409be/coded-ui-navigation/CodedUINav/Views/MainPage.cs#L88-L112
So instead of doing ItemTemplate = new DataTemplate(() => new MasterPageItemViewCell()), I would like to do ItemTemplate = new MasterPageItemTemplate(),
which results in the class
internal class MasterPageItemTemplate : DataTemplate
{
public MasterPageItemTemplate() : base(LoadTemplate)
{
}
private static Label LoadTemplate()
{
Label titleLabel = new Label();
titleLabel.SetBinding(Label.TextProperty, nameof(MasterPageItem.Title));
return titleLabel;
}
}
So I took the code from Github and modified it a little bit. When I run the code the labels content is empty and when I click on it the application crashes.
How can I fix the MasterPageItemTemplate?
Update
I found another sample that makes use of view cells
https://github.com/xamarin/xamarin-forms-samples/tree/master/WorkingWithListview/WorkingWithListview/Custom
so I think I should follow this and use this code for now
ItemTemplate = new DataTemplate(typeof(MasterPageItemViewCell)),
Data items in a ListView are called cells. Each cell corresponds to a row of data. There are built-in cells to choose from, or you can define your own custom cell. Both built-in and custom cells can be used/defined in XAML or code.The child of an inline DataTemplate must be of, or derive from, type Cell.Here in your first link sample, the ListView.ItemTemplate property is set to a DataTemplate that's created from a custom type that defines the cell appearance. The custom type derive from type ViewCell,but in your codes custom DataTemplate return a Label,it will not work.
you could refer to Creating DataTemplate
And in the sample of your second link,it use CollectionView.You could nest markup inside a DataTemplate tag to create a View.
Note :When using CollectionView, never set the root element of your DataTemplate objects to a ViewCell. This will result in an exception being thrown because CollectionView has no concept of cells.

WPB ListBox bind to control inside a class

I have a WPF ListBox of Grids that I create as follows:
I define the listbox in XAML with a simple declaration as follows:
<ListBox Name="MyListbox" >
</ListBox>
In code, I dynamically create an arbitrary number of Grid items (System.Windows.Controls.Grid), and I add them to the ListBox. Something like:
foreach (MyDataType myItem in MyDataList)
{
Grid newGrid = new Grid();
// Code that sets the properties and values of the grid, based on myItem
MyListbox.Items.Add(newGrid);
}
This works great, and everything looks the way that I want it to.
Now, I've decided that in my ListBox, I also want to store a reference to the actual myItem object, so that I can reference it later.
My idea was to create a new class like:
public class ListGridItemNode
{
public MyDataType theItem;
public Grid theGrid;
public ListGridItemNode(MyDataType inItem, Grid inGrid)
{
theItem = inItem;
theGrid = inGrid;
}
}
And then change my code to:
foreach (MyDataType myItem in MyDataList)
{
Grid newGrid = new Grid();
// Code that sets the properties and values of the grid, based on myItem
MyListbox.Items.Add(new ListGridItemNode(myItem,newGrid));
}
Of course, now my listbox instead of displaying the grids, just displays the text "MyApp.ListGridItemNode".
My question is: How do I tell the ListBox to go a level deeper and display the actual Grids inside of each ListGridItemNode object?
I suspect that this has something to do with bindings, but I can't find any examples that work the way that I'm doing it. Most of what I'm finding only shows binding to a string within an object, not an entire control.
Couldn't you just use the Tag property of the Grid object?
newGrid.Tag = myItem;
Then later:
Grid grid; // obtain Grid object somehow
MyItem myItem = (MyItem) grid.Tag;

Sharing a Binding Source Between Two Controls Not Working

I'm creating a form that will act as a master-detail editor. I have 2 controls on this form. One is basically a list of mater items and the other control is the details of the item. I'm trying to use a the same BindingSource object in both controls so that when a change is made on the master control, the detail control will get updated.
In my form I have:
EmployerCollection employerCollection = new EmployerCollection();
employerCollection.GetMulti(null, 0, new SortExpression(EmployerFields.Name | SortOperator.Ascending));
bsEmployers.DataSource = employerCollection;
masterControl.Init(bsEmployers);
detailControl.Init(bsEmpoyers);
In my masterControl I have:
public void Init(BindingSource bs)
{
bsEmployers = bs;
}
However for the life of me I can't get my master control to display the data in the binding source when I pass it in this way.
I can get binding to work only if I remove the bsEmployers = bs line and move the other logic as follows:
public void Init(BindingSource bs)
{
EmployerCollection employerCollection = new EmployerCollection();
employerCollection.GetMulti(null, 0, new SortExpression(EmployerFields.Name | SortOperator.Ascending));
bsEmployers.DataSource = employerCollection;
}
Does anyone have any idea what I can't pass the BindingSource object in to share it? I tried calling RefreshBindings in my control, but it did not seem to have any effect.
Thanks.
I don't think that the BindingSource was intended to be used that way. I would recommend passing the EmployerCollection value to the Init method and have each control create its own BindingSource using the EmployerCollection.

WPF Toolkit - Datagrid - ComboboxColumn Binding w/DynamicResource

I am implementing the WPF DataGrid (very new to WPF). I followed tutorials that showed how to bind the ComboBoxColumn using staticresources. However, the databinding for a few columns in my datagrid will not be known until runtime.
Because of this, I can't bind them with the staticresource. Is there any other way to databind the ComboBoxColumns in a DataGrid? In ASP.NET, I know we had the rowdatabound code where we could do this and dynamically create the contents of the columns. But, in WPF, it looks like everything is done through resources.
How can you databind using dynamic resources in the DataGrid?
Thanks!
You can set up bindings dynamically.
Something like this (this code creates grid view columns and assigns dynamic bindings)
private void AddColumn(GridView view, Field fld)
{
GridViewColumn col = new GridViewColumn();
col.Header = fld.Label;
Binding bnd = new Binding();
switch (fld.FieldType)
{
case FieldType.DateTime:
bnd.Converter = new DateTimeToDateStringConverter();
break;
// or some other converters
}
bnd.Path = new PropertyPath(string.Format("Fields[{0}]",
_table._fields.IndexOf(fld))); // the string matches what you would use in XAML
col.DisplayMemberBinding = bnd;
view.Columns.Add(col);
}

Categories

Resources