Display multiple local database value in listbox - c#

I'm trying to list out data from a local database to a list box for WP8.1
.xaml:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<Image Source= "**Fruit Image**" Height="26" Width="50" Margin="12,10,9,0" VerticalAlignment="Top"/>
<TextBlock Text="**Fruit Name**" FontSize="26" Style="{StaticResource BodyTextBlockStyle}"/>
<TextBlock Text="**Fruit Colour**" FontSize="26" Style="{StaticResource BodyTextBlockStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Getting value from my database
.cs:
public void ListFruit()
{
using (var db = new SQLite.SQLiteConnection(this.DBPath))
{
List<Fruits> retrievedTasks = db.Table<Fruits>().ToList<Fruits>();
}
}
.cs
public class Fruits
{
public string ImgPath { get; set; }
public string FruitName { get; set; }
public string FruitColour{ get; set; }
}
I'm not really sure if the method i'm using is correct, please guide me. Thanks!

You have defined properties in your class, you have filled your List<Fruit> with items.
What you should else do is (if you haven't done it already):
Define your List<Fruit> as ItemsSource of Listbox
public void ListFruit()
{
using (var db = new SQLite.SQLiteConnection(this.DBPath))
{
List<Fruits> retrievedTasks = db.Table<Fruits>().ToList<Fruits>();
myListbox.ItemsSource = retrievedTasks; // or directly
}
}
You may also think of using ObservableCollection instead of List - in this case you need to set ItemsSource only once - for example in constructor of the Page. You may also think of implementing INotifyPropertyChanged so that you can inform View when item changes.
And I'm not sure if you had defined Binding in your xaml (or somewhere else):
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<Image Source= "{Binding ImgPath}" Height="26" Width="50" Margin="12,10,9,0" VerticalAlignment="Top"/>
<TextBlock Text="{Binding FruitName}" FontSize="26" Style="{StaticResource BodyTextBlockStyle}"/>
<TextBlock Text="{Binding FruitColour}" FontSize="26" Style="{StaticResource BodyTextBlockStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Related

Data binding Pivot control while data binding within each Pivot items data template

So I have an ``ObservableCollection which I'm binding to a Pivot control. This ObservableCollection has a child that is also an ObservableCollection and I'm trying to bind a GridView in each Pivotitem's body.
I've tested my code-behind to ensure the collections are populated i.e.
// Level 1 ObservableCollection
foreach (var dchallenge in ChallengesList)
{
// Level 2 ObservableCollection
Debug.WriteLine(dchallenge.Name);
foreach (var dactivity in dchallenge.Activities)
{
Debug.WriteLine(dactivity.Name);
}
}
And its output is as expected.
For reference, my model is as follows:
public class Challenge
{
public string Type { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string Slug { get; set; }
public string Image { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ObservableCollection<Activity> Activities { get; set; }
public class Activity
{
public string Name { get; set; }
public string Description { get; set; }
public long Hash { get; set; }
}
}
And finally, my view:
<Pivot x:Name="Items" ItemsSource="{x:Bind ChallengesList, Mode=OneWay}" Margin="20,417,0,0">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="data:Challenge">
<TextBlock Text="{Binding Name, Mode=OneWay}" FontWeight="Normal" FontSize="16"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="data:Challenge">
<StackPanel Margin="0,20,0,0" HorizontalAlignment="Left">
<TextBlock Text="{Binding Description, Mode=OneWay}" MaxWidth="300" TextWrapping="WrapWholeWords"/>
<TextBlock Text="Activities" FontWeight="Medium" MaxWidth="300" Margin="0,20,0,0"/>
<!--<GridView DataContext="{Binding}" ItemsSource="{x:Bind Activities}" SelectionMode="None"
IsItemClickEnabled="False" IsSwipeEnabled="False" CanDragItems="False"
HorizontalAlignment="Left" Margin="0,70,0,0" VerticalAlignment="Top" Width="300">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Challenge">
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Left">
<TextBlock FontSize="16" Text="{x:Bind Name}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>-->
</StackPanel>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
A GridView may not be the control that I finally settle on, but if I know how to bind it then I should be able to use that knowledge with another control.
Intellisense helps a lot in determining which properties are available, but Activities isn't one. I only get strings such as Name and Description which work correctly (first two TextBlock).
The only problem I see is that you are using the wrong DataType in the inner GridView. The type in Activities collection is Challenge.Activity, which is a nested class and nested classes are denoted by plus sign (+) in XAML, so data:Challenge+Activity:
<GridView DataContext="{Binding}" ItemsSource="{x:Bind Activities}" SelectionMode="None"
IsItemClickEnabled="False" IsSwipeEnabled="False" CanDragItems="False"
HorizontalAlignment="Left" Margin="0,70,0,0" VerticalAlignment="Top" Width="300">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Challenge+Activity">
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Left">
<TextBlock FontSize="16" Text="{x:Bind Name}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
VS may still throw some warnings but those will disappear after successful compilation.

Listbox with UserControl ItemTemplate always shows default values

To start off, I have a listbox that is trying to accept a UserControl as the DataTemplate:
<ListBox VerticalAlignment="Stretch" Name="GeneralMcmView" Grid.Column="0" HorizontalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With the contents of the usercontrol looking like:
<ContentControl FontFamily="Segoe UI" VerticalAlignment="Stretch" FontSize="10">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding ElementName=_this, Path=TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding ElementName=_this, Path=Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding ElementName=_this, Path=MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding ElementName=_this, Path=MessageContent}" />
</StackPanel>
</Grid>
</ContentControl>
I then create a couple messages, all with different data (The Listbox's ItemSource is bound to the GeneralMessages ObservableCollection):
GeneralMcmMessage newMsg = new GeneralMcmMessage()
{
MessageId = e.McmMessageViewInfo.Id,
TimeStamp = e.McmMessageViewInfo.MessageDateTime,
Type = e.McmMessageViewInfo.MessageType.ToString(),
MessageName = e.McmMessageViewInfo.MessageName,
MessageContent = e.McmMessageViewInfo.Message.ToString()
};
GeneralMessages.Add( newMsg );
During runtime I interrogate the Items property of the listbox and all the data looks correct, however all I see in the listbox are entries of the GeneralMcmMessage User Control with default data values. Any ideas as to why?
Also, FWIW I am using INotifyPropertyChanged in the usercontrol class:
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private Constants.PiuModule piuModule = Constants.PiuModule.MCM;
private string className = "GeneralMcmMessage";
/// <summary>
/// Event for notifying listeners that a property changed. Part of INotifyPropertyChanged
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public int MessageId { get; set; }
private DateTime timeStamp;
public DateTime TimeStamp
{
get
{
return timeStamp;
}
set
{
timeStamp = value;
OnNotifyPropertyChanged( "TimeStamp" );
}
}
You're saying that the DataTemplate to display a GeneralMcmMessage is to instantiate new GeneralMcmMessage.
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
I'd recommend instead of making a collection of your UserControl to make a collection of your model object instead, and bind to the properties within that within your UserControl.
Either way though - the object you created in code will be the DataContext for the one you created in XAML so removing the ElementName=_this should bind appropriately. Try this simplified XAML in your UserControl instead.
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding MessageContent}" />
</StackPanel>
You don’t post all code of GeneralMcmMessage hence I don’t know if you set DataContext in user control for example in constructor of GeneralMcmMessage.
I tried replicate your problem.
User control GeneralMcmMessage code behind
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private int _messageId;
public int MessageId
{
get
{
return _messageId;
}
set
{
_messageId = value;
OnPropertyChanged("MessageId");
}
}
private DateTime _timeStamp;
public DateTime TimeStamp
{
get
{
return _timeStamp;
}
set
{
_timeStamp = value;
OnPropertyChanged("TimeStamp");
}
}
public GeneralMcmMessage()
{
InitializeComponent();
//don’t set data context here
//DataContext = this;
}
}
User control GeneralMcmMessage XAML
<StackPanel>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=MessageId}"/>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=TimeStamp}"/>
</StackPanel>
User control GeneralMcmMessage usage
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<GeneralMcmMessage> _generalMessages;
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<GeneralMcmMessage> GeneralMcmMessages
{
get { return _generalMessages; }
set
{
_generalMessages = value;
OnPropertyChanged("GeneralMcmMessages");
}
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
GeneralMcmMessages = new ObservableCollection<GeneralMcmMessage>();
for (int i = 0; i < 10; i++)
{
var newMsg = new GeneralMcmMessage
{
MessageId = i,
TimeStamp = DateTime.Now,
};
GeneralMcmMessages.Add(newMsg);
}
}
}
User control GeneralMcmMessage usage XAML
<ListBox x:Name="ListBox"
Margin="5"
ItemsSource="{Binding Path=GeneralMcmMessages}">
<ListBox.ItemTemplate>
<DataTemplate DataType="stackoverflow:GeneralMcmMessage">
<stackoverflow:GeneralMcmMessage/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If this not solve your problem could you please post all GeneralMcmMessage?
If you want I can upload sample project for you.
Thank you

Bind a textblock in a nested list member

I have these classes:
public class Datum
{
public string name{get;set;}
public string id{get;set}
public List<Brewery> breweries { get; set; }
.
.
}
public class Brewery
{
public string name { get; set; }
.
.
}
And this Listbox
<ListBox ItemsSource="{Binding}" HorizontalAlignment="Left" Height="580" Margin="0,80,0,0" VerticalAlignment="Top" Width="446">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem Tap="ListBoxItem_Tap" Tag="{Binding Path=id}">
<TextBlock Name="First" Text="{Binding Path=name}" />
<TextBlock Name="Second" Foreground="Gray" Text="{Binding Path=breweries.name}" />
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So I create a list of Datum objects and I bind the listbox to it. In that way, the First textblock is bound to the property 'name' of the Datum class.That works perfectly. What I want is the Second textblock to be bound to the property 'name', of the first item of the Brewery list.
If breweries was not a List I would easily do that, but since I take the info from a json, I can't change that.
From your example, if I understand what you're doing correctly, you should just be able to use an index to bind to the desired item from the collection. I'm not sure it's the best approach, but it should yield the result you're after.
E.g. (adapting your example):
<ListBox ItemsSource="{Binding}" HorizontalAlignment="Left" Height="580" Margin="0,80,0,0" VerticalAlignment="Top" Width="446">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ListBoxItem Tap="ListBoxItem_Tap" Tag="{Binding Path=id}">
<TextBlock Name="First" Text="{Binding Path=name}" />
<TextBlock Name="Second" Foreground="Gray" Text="{Binding Path=breweries[0].name}" />
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Binding a list to a Gridview

I'm struggling to get my head around this, i have a list collection with the following that i'm trying to bind to a GridView;
public class GetMenu
{
public string titleName { get; set; }
public string imagePath { get; set; }
}
List<GetMenu> Menu = new List<GetMenu>()
{
new GetMenu(){titleName = "one", imagePath = "image.jpg"},
new GetMenu(){titleName = "one", imagePath = "image.jpg"}
};
My XAML code looks like;
<GridView x:Name="MenuViewGrid" TabIndex="1"
Grid.RowSpan="2" Padding="116,136,116,46" Margin="0,0,50,0" VerticalAlignment="Center"
SelectionMode="None" IsSwipeEnabled="false" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="275" Height="425" >
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Path=imagePath}" Stretch="UniformToFill"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Path=titleName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" FontSize="25" Height="60" Margin="15,0,15,0"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
In my head i thought i'd be able to do a simple;
MenuViewGrid.ItemsSource = GetMenu;
But when doing the above i get an error message saying it's a type but i'm trying to use it as a variable. I can't understand this as i've used the code on Windows Phone before.
Replace GetMenu by Menu (GetMenu is your class, Menu is your list):
MenuViewGrid.ItemsSource = Menu;

WPF: What's the proper way to do nested Binding

I have 3 models: Machine, Part, and Component. On my ui, I have bound one listbox to a list of Machines and a second listbox to the selected Machine's list of Parts. Now when the user selects a part, I would like to bind a datagrid to the selected part's list of components. I tried setting the datagrid's itemssource to:
ItemsSource="{Binding ElementName=PartSelectList, Path=SelectedItem.Components}"
I also tried setting its datacontext and itemssource
DataContext={Binding ElementName=PartSelectList, Path=SelectedItem}
ItemsSource={Binding Components}
However the datagrid does not automatically update if changes are made to the part's list of components via methods such as
part.Bags.Add(new Component(..));
Anyone have suggestions on how I should approach this?
Update: I have a class MachineCollection which implements INotifyPropertyChanged. In my xaml.cs code I create my MachineCollection object and bind the MainGrid to it's Machines property:
Page1.xaml.cs:
private MachineCollection machines
public Page1()
{
machineCollection = new MachineCollection();
MainGrid.DataContext = machineCollection.Machines
actionThread = new Thread(InitLists);
actionThread.Start();
}
public void InitLists()
{
machineCollection.Machines.AddRange(dbCon.GetAllMachines());
}
Classes:
public class MachineCollection : INotifyPropertyChanged
{
public List<Machine> Machines
{
get { return machines; }
set { machines = value; NotifyPropertyChanged("Machines"); }
}
}
public class Machine : INotifyPropertyChanged
{
public List<Part> Parts
{
get { return parts; }
set { parts = value; NotifyPropertyChanged("Parts");
}
}
public class Part : INotifyPropertyChanged
{
public List<Component> Components
{
get { return components; }
set { components = value; NotifyPropertyChanged("Components");
}
}
public class Component : INotifyPropertyChanged
{
public int Length
{
get { return length; }
set { length = value; NotifyPropertyChanged("Length");
}
}
XAML:
<Page>
<Grid Name="MainGrid">
<ListBox x:Name="MachineSelectList" HorizontalAlignment="Left" VerticalAlignment="Bottom"
Height="114" Width="231"
Foreground="White" Background="#FF7A7A7A" FontSize="16" BorderBrush="#FFC13131"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="200">
<TextBlock Text="{Binding SerialNumber}" TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Button Name="DeleteMachine" Tag="{Binding SerialNumber}" HorizontalAlignment="Right" VerticalAlignment="Center" Height="20"
Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Focusable="False" Click="Btn_Click" >
<Image Source="..\Resources\Images\delete.png" Stretch="Uniform"/>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="PartSelectList" HorizontalAlignment="Left" VerticalAlignment="Bottom"
Height="164" Width="231"
Background="#FF7A7A7A" Foreground="White" FontSize="16" BorderBrush="#FFC13131"
ItemsSource="{Binding Path=Parts}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="200">
<TextBlock Text="{Binding PartNumber}" TextAlignment="Left" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Button Name="DeletePart" Tag="{Binding PartNumber}" HorizontalAlignment="Right" VerticalAlignment="Center" Height="20"
Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Focusable="False" Click="Btn_Click" >
<Image Source="..\Resources\Images\delete.png" Stretch="Uniform"/>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Page>
One way to solve this is using ObservableCollection, which is made for situations like this.
public ObservableCollection<Part> Parts
{
get { return parts; }
set { parts = value; NotifyPropertyChanged("Parts");
}
Or you could implement the interface INotifyCollectionChanged manually
The problem is, basically, that the binding system does not know when you call Add. If you were reassigning the Parts property each time, then the system would just redraw everything, so it would reflect the changes too, but if ObservableCollection is not a problem, that's the prefered way

Categories