WPF ItemsSource binding show only last item of list - c#

How to show only last item of the list in itemssource binding ?
below is my current code.
xaml
<ItemsControl ItemsSource="{Binding UpgradeTicketStorage}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Width="800">
<TextBlock Text="{Binding TicketTitle}" Style="{StaticResource TicketSelectionSubTitle}" TextAlignment="Left" />
<TextBlock Text="{Binding TicketDescription}" TextWrapping="Wrap" Style="{StaticResource TicketSelectionSubTitle2}" FontSize="19" TextAlignment="Left"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
from class binding i do have added 2 records which is ticketA and ticketB, how can i just display ticketB information ? instead of A and B
class
public class UpgradeTicketDescription : ViewModelBase
{
public string TicketTitle { get; set; }
public string TicketDescription { get; set; }
}
List<UpgradeTicketDescription> _UpgradeTicketStorage;
public List<UpgradeTicketDescription> UpgradeTicketStorage
{
get { return _UpgradeTicketStorage; }
set { _UpgradeTicketStorage = value; OnPropertyChanged("UpgradeTicketStorage"); }
}
UpgradeTicketStorage.Add(new UpgradeTicketDescription { TicketTitle = "TicketA", TicketDescription = "Observation DeckA (Single Ticket)"});
UpgradeTicketStorage.Add(new UpgradeTicketDescription { TicketTitle = "TicketB", TicketDescription = "Observation DeckB (Single Ticket)"});

If you want to bind to a specific item in a list you can go about it by creating a public variable you will bind to. Using what you have provided I've created an example that works for the last item in the list, all I did is create a new variable called LastItem and changed how the binding is in the project. This is just one of many ways of going about this.
xaml
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Width="800">
<TextBlock Text="{Binding LastItem.TicketTitle}" TextAlignment="Left" />
<TextBlock Text="{Binding LastItem.TicketDescription}" TextWrapping="Wrap" FontSize="19" TextAlignment="Left"/>
</StackPanel>
class
public UpgradeTicketDescription LastItem
{
get { return UpgradeTicketStorage.Last(); }
}
This provides this output:

Related

Inputted Items sometimes appear empty in Data grid

I have ItemsControl and a DataGrid in a WPF UserControl. this is how it looks like
when the "Add to card" button is pressed a ViewModel instance is added to ObservableCollection bound to the DataGrid.
<ItemsControl
ItemsSource="{Binding Meals}"
x:Name="MealList"
Margin="5">
<ItemsControl.ItemTemplate>
<DataTemplate>
<components:MealCardCustomer
BorderBrush="OrangeRed"
BorderThickness="5px"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<DataGrid
HorizontalAlignment="Stretch"
IsReadOnly="True"
Background="Orange"
x:Name="OrderedMeals"
SelectionMode="Single"
ItemsSource="{Binding OrderedMeals, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
SelectedIndex="{Binding SelectedOrderedMeal, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
FontSize="26"
Grid.Column="0"
Grid.Row="0"
Margin="5"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name, Mode=OneWay}" Header="Name" />
<DataGridTextColumn Binding= "{Binding Price, Mode=OneWay}" Header="Price" />
<DataGridTextColumn Binding="{Binding Ingredients, Mode=OneWay}" Header="Ingredients" />
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
The problem is that sometimes when I add new items it appears like an empty column.
I tried to add a button which refreshes the data grid but when pressed it makes the all of the items blank.
Also I've wrapped the DataGrid in a ScrollViewer with a horizontal scroll which for some reason doesn't work.
That's the ViewModel of the View
private string? address;
public string? Address
{
get { return address; }
set { address = value; OnPropertyChaneg(nameof(Address)); }
}
private int selectedOrderedMeal = -1;
public int SelectedOrderedMeal
{
get { return selectedOrderedMeal; }
set { selectedOrderedMeal = value; OnPropertyChaneg(nameof(SelectedOrderedMeal)); }
}
private ObservableCollection<MealCardCustomerViewModel> meals;
public ObservableCollection<MealCardCustomerViewModel> Meals
{
get { return meals; }
set { meals = value; }
}
private ObservableCollection<MealCardCustomerViewModel> orderedMeals;
public ObservableCollection<MealCardCustomerViewModel> OrderedMeals
{
get { return orderedMeals; }
set { orderedMeals = value; OnPropertyChaneg(nameof(OrderedMeals)); }
}
public BaseCommand RemoveCommand { get; }
public BaseCommand FinishOrderCommand { get; }
public NavigateCommand NavigateToCustomerListOfOtders { get; }
public BaseCommand LoadMealsCommand { get; }
public CustomerOrderingViewModel(NavigationService customerListOfOrdersNavigationService, NavigationService helpNavigationService, IMealService mealService)
: base(helpNavigationService, mealService)
{
Meals = new ObservableCollection<MealCardCustomerViewModel>();
OrderedMeals = new ObservableCollection<MealCardCustomerViewModel>();
RemoveCommand = new RemoveMeal(this);
FinishOrderCommand = new FinishOrder(this, customerListOfOrdersNavigationService);
NavigateToCustomerListOfOtders = new NavigateCommand(customerListOfOrdersNavigationService);
LoadMealsCommand = new LoadMeals<CustomerOrderingViewModel>(this);
}
public static CustomerOrderingViewModel LoadViewModel(NavigationService customerListOfOrders, NavigationService helpNavigationService, IMealService mealService)
{
CustomerOrderingViewModel viewModel = new CustomerOrderingViewModel(customerListOfOrders, helpNavigationService, mealService);
viewModel.LoadMealsCommand.Execute(null);
return viewModel;
}
public override void LoadMealsList(List<Meal> meals)
{
Meals.Clear();
foreach (var meal in meals)
{
Meals.Add(new MealCardCustomerViewModel(meal,this));
}
}
That the Views which act like ItemTemplates for the ItemsControl
<Image
Source="{Binding MealImage, Converter ={StaticResource imageConverter}, Mode=TwoWay, TargetNullValue=DefaultImage}"
Stretch="Uniform"/>
<DockPanel
Grid.Row="1"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Name :"/>
<TextBox
Text="{Binding Name,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FontSize="20"
Margin="5"/>
</DockPanel>
<DockPanel
Grid.Row="2"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Price :"/>
<TextBox
Text="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:f2}}"
FontSize="20"
Margin="5"/>
</DockPanel>
<DockPanel
Grid.Row="3"
VerticalAlignment="Center"
Margin="5">
<TextBlock
FontSize="20"
Margin="5"
Text="Ingredients:"/>
<TextBox
Text="{Binding Ingredients, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FontSize="20"
Margin="5"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
/>
</DockPanel>
<Button
Command="{Binding AddToCardCommand}"
Background="OrangeRed"
Grid.Row="4"
Margin="10 5 10 5"
Content="Add to cart"
FontSize="20"/>
and that's the command that adds the item to the ObservableCollection
private CustomerOrderingViewModel customerOrderingViewModel;
private MealCardCustomerViewModel mealCardCustomerViewModel;
public AddToCard(CustomerOrderingViewModel customerOrderingViewModel, MealCardCustomerViewModel mealCardCustomerViewModel)
{
this.customerOrderingViewModel = customerOrderingViewModel;
this.mealCardCustomerViewModel = mealCardCustomerViewModel;
}
public override void Execute(object? parameter)
{
customerOrderingViewModel.OrderedMeals.Add(mealCardCustomerViewModel);
}
The problem was with the images in the objects which are non existing right now and so they are null.
For some reason the null value cause infinite loop in the converter and so the view models could not load the properties of the entity but the collection could read that the count was changed thus displaying the empty rows.
The way you add items to the cart is not thread safe.
Immagine the AddToCart() being called wich will update your customerOrderingViewModel and mealCardCustomerViewModel. Then immagine that before Execute is called, some other thread changes customerOrderingViewModel or mealCardCustomerViewModel. This could result in Execute() adding the wrong (or a Null) meal to your order.
If that is the reason for your error, the following code shoud solve it:
public AddToCard(CustomerOrderingViewModel customerOrderingViewModel, MealCardCustomerViewModel mealCardCustomerViewModel)
{
customerOrderingViewModel.OrderedMeals.Add(mealCardCustomerViewModel);
this.customerOrderingViewModel = customerOrderingViewModel;
this.mealCardCustomerViewModel = mealCardCustomerViewModel;
}
If you dont need customerOrderingViewModel and mealCardCustomerViewModel in the class owning AddToCart(), you could even spare those variables completely.
Side note:
If you dont plan on changing the observable collections but only their content, you can simply declare them as public fiels and not as propertys. The setter of the propertys wil only be accessed when thwo whole ObservableCollection object is changed but not if its content is changed. PropertyChanged notifications for changes inside the ObservableCollection are handlled by the ObservableCollection implementation.

How to make the SelectedItem in Combobox(customize DataTemplate) shows only specific property of the item

I have a ComboBox that shows a list of information:
NameOfEstablishment
BIN
Owner
BusinessAddress
...appearing like so:
Code:
<ComboBox x:Name="BploList"
Text="{Binding Search}"
SelectedItem="{Binding SearchSelected}"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
FontSize="16"
materialDesign:HintAssist.Hint="Search"
Margin="5 5 65 5"
IsEditable="True">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding NameOfEstablishment}" FontSize="12" Foreground="#D8AC6A"
TextWrapping="Wrap" MaxWidth="250" />
<TextBlock Text="{Binding BIN}" FontSize="11" TextWrapping="Wrap" MaxWidth="250" />
<TextBlock Text="{Binding Owner}" FontSize="11" TextWrapping="Wrap" MaxWidth="250" />
<TextBlock Text="{Binding BusinessAddress}" FontSize="11" TextWrapping="Wrap" MaxWidth="250" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
Problem
SelectedItem should show the NameOfEstablishment value only but it instead shows as the full object:
As for Source of ComboBox
private BindingList<BPLOSearchModel> _bploList;
public BindingList<BPLOSearchModel> BploList
{
get { return _bploList; }
set
{
_bploList = value;
NotifyOfPropertyChange(() => BploList);
}
}
Properties of BPLOSearchModel
public class BPLOSearchModel
{
public string BIN { get; set; }
public string NameOfEstablishment { get; set; }
public string BusinessAddress { get; set; }
public string Owner { get; set; }
}
As for SearchSelected
private string _searchSelected;
public string SearchSelected
{
get { return _searchSelected; }
set
{
_searchSelected = value;
NotifyOfPropertyChange(() => SearchSelected);
}
}
This is exactly what SelectedValuePath is for. It is used to
get or set the path that is used to get the SelectedValue of the SelectedItem
In your case, set it like
<ComboBox ... SelectedValuePath="NameOfEstablishment" ... />
Note that there is also a nice How to at Microsoft.

DataContext Gridview within Stack Panel in XAML Windows Phone 8

I'm trying to data bind a collection ("Dashboard") that contains a ObservableCollection property.
I have managed to databind the dashboard class without any issues. I cant however work out how to databind to the Release collection that is contained within the dashboard class.
The issue seems to be on the GridView which is databound to the Releases property of the Dashboard class. The Stack Panel around the GridView is working correctly.
The classes
public class Dashboard
{
public Dashboard(String id, String projectName)
{
this.Id = id;
this.ProjectName = projectName;
this.Releases = new ObservableCollection<Release>();
}
public string Id { get; private set; }
public string ProjectName { get; private set; }
public ObservableCollection<Release> Releases { get; private set; }
public override string ToString()
{
return this.ProjectName;
}
}
public class Release
{
public Release(string environmentName, string releaseVersion, string state, string releaseDate)
{
EnvironmentName = environmentName;
ReleaseVersion = releaseVersion;
State = state;
ReleaseDate = releaseDate;
}
public string EnvironmentName { get; private set; }
public string ReleaseVersion { get; private set; }
public string State { get; private set; }
public string ReleaseDate { get; private set; }
}
The XAML
<HubSection x:Uid="Dashboard" x:Name="Dashboard" Header="Dashboard" DataContext="{Binding Dashboard}">
<DataTemplate>
<GridView x:Uid="DashboardGrid" x:Name="DashboardGrid" ItemsSource="{Binding}" ItemTemplate="{StaticResource Standard200x180TileItemTemplate}" >
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</DataTemplate>
</HubSection>
The data template
<DataTemplate x:Key="Standard200x180TileItemTemplate">
<StackPanel DataContext="{Binding}" >
<TextBlock Text="{Binding ProjectName}" Grid.Column="0" Style="{ThemeResource BaseTextBlockStyle}" Typography.Capitals="SmallCaps" Grid.Row="0" IsTextScaleFactorEnabled="False"/>
<GridView Grid.Row="1" DataContext="{Binding Releases}">
<TextBlock Text="{Binding EnvironmentName}" />
<TextBlock Text="{Binding ReleaseVersion}" />
<TextBlock>hello</TextBlock>
<Border Background="#FF0CB90C" Height="110" Width="110" HorizontalAlignment="Left" Margin="0,0,10,0">
</Border>
</GridView>
</StackPanel>
</DataTemplate>
Set ItemsSource of GridView not DataContext and then use another DataTemplate
<StackPanel>
<TextBlock Text="{Binding ProjectName}" Grid.Column="0" Style="{ThemeResource BaseTextBlockStyle}" Typography.Capitals="SmallCaps" Grid.Row="0" IsTextScaleFactorEnabled="False"/>
<GridView Grid.Row="1" ItemsSource="{Binding Releases}">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding EnvironmentName}" />
<TextBlock Text="{Binding ReleaseVersion}" />
<TextBlock>hello</TextBlock>
<Border Background="#FF0CB90C" Height="110" Width="110" HorizontalAlignment="Left" Margin="0,0,10,0">
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</StackPanel>

DataBinding to WP8 Toolkit ExpanderView

I'm attempting to databind to a Windows Phone 8 Toolkit Expander view with the following XAML and C# class. I know that the DataContext is set properly because the Headers have the proper text. However, the rest of the items aren't set properly (except for the ExpanderTemplate)
<phone:PanoramaItem Header="Skill Sheet">
<ListBox Name="SkillSheet" ItemsSource="{Binding}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}"
ItemsSource="{Binding}"
IsNonExpandable="False">
<toolkit:ExpanderView.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding groupName}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" LineHeight="{StaticResource LongListSelectorGroupHeaderFontSize}" />
</DataTemplate>
</toolkit:ExpanderView.HeaderTemplate>
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<TextBlock Text="Test" />
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<!--This is the area that is not getting databound-->
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding skillNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding skill}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</phone:PanoramaItem>
And here are the classes that the XAML is getting bound to:
public class TreeMapSkill
{
public string skill { get; set; }
}
public class TreeMapping
{
public string groupName { get; set; }
public List<TreeMapSkill> skillNames { get; set; }
public TreeMapping()
{
skillNames = new List<TreeMapSkill>();
}
}
public class TreeMappingList
{
public List<TreeMapping> mapping { get; set; }
public TreeMappingList() { }
public TreeMappingList(Dictionary<string, List<string>> map)
: base()
{
this.mapping = new List<TreeMapping>();
foreach (string key in map.Keys)
{
TreeMapping tMap = new TreeMapping();
tMap.groupName = key;
foreach (string val in map[key])
tMap.skillNames.Add(new TreeMapSkill() { skill = val });
this.mapping.Add(tMap);
}
}
The Dictionary in the constructor is simply a list of skills associated to a specific group. I can also provide a sample object if it's needed for additional reference.
Why are you adding a ListBox inside the Expander's ItemTemplate? It is already a controls collection so you don't need a ListBox in there. Just put your DataTemplate inside.
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding skill}" />
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
The second thing is you need to specify the property path on the binding of the ItemSource property for the expander.
<toolkit:ExpanderView Header="{Binding}"
ItemsSource="{Binding skillNames}"
IsNonExpandable="False">

ListBox with 2 kind of rows

I use this code to create the ListBox in the XAML :
<ListBox Margin="20,96,20,20" ItemsSource="{Binding Items}" Name="ResultsListBox" SelectionChanged="ResultsListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And this is the code that i insert the strings(list is a List of String):
ResultsListBox.ItemsSource = list;
Now i want the possible to create this listbox with array of items that contain:
string name
string id
string imageurl
Can i combine the this to kind of lists?
Create a class like this
public class SomeClass
{
string name { get; set; }
string id { get; set; }
string imageurl { get; set; }
}
Then change your xaml like this
<ListBox Margin="20,96,20,20" ItemsSource="{Binding Items}" Name="ResultsListBox" SelectionChanged="ResultsListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding name}" />
<TextBlock Text="{Binding id}" /> <!-- ignore id if you don't want -->
<TextBlock Text="{Binding imageurl}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, generate a collection or list to bind to the listbox
List<SomeClass> list = new List<SomeClass>();
list.Add(new SomeClass() { name = "some name", id = "some id", imageurl = "some url" });
list.Add( .....);
ResultsListBox.ItemsSource = list;

Categories

Resources