In wpf Clear ListBox items at Runtime - c#

I am using wpf listbox, i cannot able to clear the list when am calling the reload data function, i just want to reload new data at runtime,while page loading it loads the data correctly, when i refresh the new data is fetched in itemsource i can see that in debug mode, but no new data in listbox, old data remains in the list, i cant even clear, when i call list.items.clear(), i tried lot ways, is there any problem in my XAML binding, the following is my code.
XAML:
<ListBox ItemsSource="{Binding}" HorizontalContentAlignment="Left" x:Name="lstbxindex" Foreground="White" FontSize="20px" Height="400" BorderBrush="#555555" Margin="10,34,16,0" VerticalAlignment="Top" Width="322" Background="#555555" >
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel Orientation="Horizontal" Margin="5" >
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="txtblckroundhour" Height="40px" Width="55px" Text="{Binding RoundedHours}" FontSize="14" Background="#555555" Loaded="txtblckroundhour_Loaded" Foreground="White"></TextBlock>
<Label x:Name="items" MouseDoubleClick="items_MouseDoubleClick" Content="{Binding ProjectRow.Name}" Background="#555555" FontSize="20" Loaded="items_Loaded" Visibility="Visible" Margin="35,0,0,0" Width="230" Foreground="White"></Label>
</StackPanel>
<StackPanel Orientation="Vertical">
<ComboBox Height="40px" Width="290" Margin="-230,0,0,0" Loaded="ComboBox_Loaded" Visibility="Hidden" IsEditable="True" FontSize="20" Background="White" Foreground="Black"></ComboBox>
</StackPanel>
<!--<ComboBox x:Name="ComboBox_AddItem" Height="40px" Width="290" Margin="-35,35,0,0" Loaded="ComboBox_AddItem_Loaded" IsEditable="True" FontSize="20" Background="White" Visibility="Hidden" Foreground="Black"></ComboBox>-->
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Get the list of values
private List<ProjectInformation> projectInformationList1 = new List<ProjectInformation>();
// Here define the actual binding of the userinterface listbox to the in-memory list of objects.
foreach (DtoProjectsRow row in projectsTable.Rows)
{
projectInformationList1.Add(new ProjectInformation(row));
}
lstbxindex.DataContext = projectInformationList1;
In SO I tried some solution but unfortunately it is not work for me. Last I tried,
XAML.cs page
public static readonly DependencyProperty MyListProperty = DependencyProperty.Register("MyList", typeof(ObservableCollection<String>), typeof(Window));
public ObservableCollection<String> MyList
{
get
{
return (ObservableCollection<String>)GetValue(MyListProperty);
}
set
{
SetValue(MyListProperty, value);
}
}
XAML:
<ListBox ItemsSource="{Binding **ElementName=Window**}" HorizontalContentAlignment="Left" x:Name="lstbxindex" Foreground="White" FontSize="20px" Height="400" BorderBrush="#555555" Margin="10,34,16,0" VerticalAlignment="Top" Width="322" Background="#555555" >
Using this above solution listitems are clear but when pageloading the listboxitems are clear but I don't want to clear the iistboxitems, after updating the values from user it will reload the updated value in listbox.
lstbxindex.ItemsSource = null;
But its not work.For pageload listbox loaded all items,every 15 min interval it will call the load function for firsttime it will reload the updatedvalues but second time it will reload the updated values and previous values remains in listbox again.

I misunderstood initially thinking you were using MVVM, instead you're populating the ListView datasource from code behind.
Your line lstbxindex.DataContext = projectInformationList1; does not set the Data as you'd think. Instead try lstbxindex.DataContext = this; which means you're telling your view to look for the data source in code behind.
As such, I suggest adding using System.ComponentModel; and using BindingList, a comparison is here.
private BindingList<ProjectInformation> projectInformationList1 = new BindingList<ProjectInformation>();
And you just need this once:
foreach (DtoProjectsRow row in projectsTable.Rows)
{
projectInformationList1.Add(new ProjectInformation(row));
}
lstbxindex.DataSource = projectInformationList1;
As mentioned in the comments, if you did not use ItemsSource="{Binding projectInformationList1}" as I suggested in a comment to your question, this is the alternative:
private ObservableCollection<ProjectInformation> projectInformationList1 = new ObservableCollection<ProjectInformation>();
foreach (DtoProjectsRow row in projectsTable.Rows)
{
projectInformationList1.Add(new ProjectInformation(row));
}
lstbxindex.DataContext = projectInformationList1;

You should have a view model class with a collection property, e.g. like this:
public class ViewModel
{
public ObservableCollection<ProjectInformation> Projects { get; }
= new ObservableCollection<ProjectInformation>();
}
Set the DataContext of your Window or Page in XAML like this:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
and bind the ListBox like this:
<ListBox ItemsSource="{Binding Projects}">
...
</ListBox>
To clear all items in the source collection, access the DataContext in code behind:
var vm = (ViewModel)DataContext;
vm.Projects.Clear();
Edit: Instead of assigning the DataContext in XAML, you may as well do it in code behind, even before the Page or Window is initialized:
public MainWindow()
{
DataContext = new ViewModel();
InitializeComponent();
}

Added the line in loadfunction, Initially set null for ItemSource and then set null to the list object
lstbx.ItemsSource=null;
lstbx.Items.Clear();
ProjectInfoList1=null;
it will clear the listboxitems and reload with updated values only.
private BindingList<ProjectInfo> projectInfoList1 = new BindingList<ProjectInfo>();
Public void loadfunction()
{
lstbx.ItemsSource=null;
lstbx.Items.Clear();
ProjectInformationList1=null;
foreach (DtoProRow row in table.Rows)
{
projectInfoList1.Add(new ProjectInfo(row));
}
lstbx.DataContext = projectInfoList1;
}

Related

UWP update a itemscontrol with an array that keeps updating

I have an array that keeps changing its values, because of this I want to have the apps UI refreshing every time the array's values do. I have this bound with an itemsControl. I can show the first array's values but then I can't update them I have tried .items.Clear() but its not working. Here are snippets of the .xaml and the xaml.cs. I actually took the code of the .xaml from a question from this site.
.xaml
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="Testing" IsReadOnly="True"></TextBox>
<ItemsControl x:Name="itemsControl"
ItemsSource="{Binding itemsControl}"
FontSize="24">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="Auto"
Margin="0 12"
HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Column="0"
Grid.Row="0"
Orientation="Horizontal">
<TextBlock Name="txtblk0" Text="{Binding}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
.xaml.cs
String c = (new String(cArray));
string[] arr = null;
string[] data = null;
if (c != null)
{
arr = c.Split('\n');
if (arr.Length > 0)
{
data = arr[0].Split(',');
}
}
for(int index = 0; index < 4; index++)
{
itemsControl.Items.Add(float.Parse(data[index]));
}
itemsControl.Clear();
If anyone has an idea of how I can do this I will be very grateful, thanks in advance and I will try to answer any questions as soon as possible!
What you're missing is an understanding of how bindings are triggered to update.
The INotifyPropertyChanged interface contains a method (PropertyChanged) and when called and passed the name of a property will tell the binding system that the property has changed and the binding should be updated.
INotifyCollectionChanged is the equivalent for collections, and communicates when a collection has changed. i.e. something added, removed, or the list cleared.
ObservableCollection<T> contains an implementation of INotifyCollectionChanged that makes it easy to work with lists, collections, etc. that change.
If you used an ObservableCollection<float> instead of an array you'd be able to modify the list and have the UI updated to reflect this easily.
As a starter, see the following which demonstrates how easy it is to use an ObservableCollection.
XAML:
<StackPanel>
<Button Click="Button_Click">add an item</Button>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
code behind;
public MainPage()
{
this.InitializeComponent();
// Initialize the property
this.Items = new ObservableCollection<string>();
// Use self as datacontext (but would normally use a separate viewmodel)
this.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// add a new item to the UI
this.Items.Add(DateTime.Now.ToString());
}
// The "collection" that is shown in the UI
public ObservableCollection<string> Items { get; set; }

secondary listbox not show data

i've two listbox binded with properties of my viewmodel, the first listbox shows LstEmpresas and work fine, when I select a item, the property SelectedCompany sets fine, all ok.
In SelectedCompany's set of my viewmodel, I call a method than pupulate a secondary list (LtsEjercicios) and work fine too (LtsEjercicios populate perfectly depends that item i've selected in the first listbox).
The secondary listbox binds his ItemSource from LtsEjercicios object that, across viewmodel, is updated.
But the secondary listbox NOT SHOW any data, i'm crazy yet.
This viewModel code
public class frmEmpresasVM : ViewModelBase
{
//propiedades
EmpresasDataAccess empresasController = new EmpresasDataAccess();
private ObservableCollection<EmpresasTable> lstEmpresas;
private ObservableCollection<EmpresasEjerciciosTable> ltsEjercicios;
public ObservableCollection<EmpresasTable> LstEmpresas
{
get
{
return lstEmpresas;
}
set
{
lstEmpresas = value; RaisePropertyChanged("LstEmpresas");
}
}
public ObservableCollection<EmpresasEjerciciosTable> LtsEjercicios
{
get
{
return ltsEjercicios;
}
set
{
ltsEjercicios = value; RaisePropertyChanged("LtsEjercicios");
}
}
//selected company in listbox
private int selectedCompany;
public int SelectedCompany
{
get
{
return selectedCompany;
}
set
{
selectedCompany = value;
LtsEjercicios = empresasController.SelectExercicesById(selectedCompany.ToString());
RaisePropertyChanged("SelectedCompany");
}
}
//main constructor, default values for lists
public frmEmpresasVM()
{
LstEmpresas = empresasController.SelectOnlyNames();
LtsEjercicios = empresasController.SelectExercicesById("0");
}
and, XAML for the view
<ListBox x:Name="companyList" HorizontalAlignment="Left" Height="205" Margin="20,30,0,0" VerticalAlignment="Top" Width="450" ItemsSource="{Binding LstEmpresas, Mode=OneWay}" SelectedValue="{Binding SelectedCompany, Mode=TwoWay}" SelectedItem="{Binding LtsEjercicios, Mode=OneWay}" SelectedIndex="0" DisplayMemberPath="Nombre" SelectedValuePath="Id" IsSynchronizedWithCurrentItem="True" SelectionChanged="companyList_SelectionChanged_1">
<ListBox.ItemBindingGroup>
<BindingGroup/>
</ListBox.ItemBindingGroup>
<ListBox.DataContext>
<InnovaCommerceHosteleryViewModels:frmEmpresasVM/>
</ListBox.DataContext>
</ListBox>
<TextBlock x:Name="lblEjercicio" HorizontalAlignment="Left" Height="20" Margin="475,10,0,0" TextWrapping="Wrap" Text="Ejercicios" VerticalAlignment="Top" Width="95"/>
<ListBox x:Name="excercicesList" HorizontalAlignment="Left" Height="205" Margin="475,30,0,0" VerticalAlignment="Top" Width="110" ItemsSource="{Binding LtsEjercicios, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Ejercicio" SelectedValuePath="Id" SelectedIndex="0" IsSynchronizedWithCurrentItem="True">
<ListBox.DataContext>
<InnovaCommerceHosteleryViewModels:frmEmpresasVM/>
</ListBox.DataContext>
Al Data provides from a MySQL Database from both tables (empresas y empresas_ejercicios).
My goal is, when user select a item in listbox1 (empresas) show exercices in listbox2 (empresas_ejercicios).
If exist other path to determine this operation, i'm all eyes!!!
Thanks in advance.
Not sure if this is the only problem in your code, but what you're doing by setting
<ListBox.DataContext>
<InnovaCommerceHosteleryViewModels:frmEmpresasVM/>
</ListBox.DataContext>
for both list boxes is creating a separate instance of the ViewModel for each list box. Now I guess if you make any changes in the first list box' ViewModel instance, these changes will not be reflected in the second list box because this one binds to a totally different ViewModel instance.
Instead, try globally binding the ViewModel to the whole window / page / user control / etc. (depending on whether you;re doing WPF, Windows Phone, etc.), and let the list boxes inherit it to ensure that only one ViewModel instance is involved:
<Window.DataContext>
<InnovaCommerceHosteleryViewModels:frmEmpresasVM/>
</Window.DataContext>
EDIT:
Alternatively, you might as well instantiate the ViewModel once and store it as global resource:
<Window.Resources>
<InnovaCommerceHosteleryViewModels:frmEmpresasVM x:Key="Viewmodel" />
</Window.Resources>
and in the listboxes' DataContext just reference this global resouce:
<ListBox DataContext="{StaticResource Viewmodel}" ... />

binding data - inotifypropertychanged does not work

I have a listBox1 in which data are binding from the list. Then I want to when I select any item from listBox1 in listBox2 will binding data from another list.
private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Teams teams = (Teams)listBox1.SelectedItems[0];
getH2hResults("//td[#class='hell']", teams.Team1, teams.Team2); // add elements to list
getH2hResults("//td[#class='dunkel']", teams.Team1, teams.Team2); // and here also
listBox2.ItemsSource = lists.h2hList;
}
On the first time this work, but for the twice time listBox2 doesn't displays new data.
public class Lists : BindableBase
{
public Lists()
{
_teamsList = new List<Teams>();
_h2hList = new List<H2H>();
}
private List<Teams> _teamsList;
public List<Teams> teamsList
{
get
{
return _teamsList;
}
set
{
if (value != _teamsList)
{
_teamsList = value;
RaisePropertyChanged("teamsList");
}
}
}
private List<H2H> _h2hList;
public List<H2H> h2hList
{
get
{
return _h2hList;
}
set
{
if (value != _h2hList)
{
_h2hList = value;
RaisePropertyChanged("h2hList");
}
}
}
}
And XAML
<ListBox Name="listBox1" Width="300" Height="300"
VerticalAlignment="Top"
HorizontalAlignment="Left"
ItemsSource="{Binding teamsList}" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="#FF4273CD" Text="{Binding Team1, Mode=TwoWay}"></TextBlock>
<TextBlock Text=" vs " FontWeight="Bold"></TextBlock>
<TextBlock Foreground="#FF4273CD" Text="{Binding Team2, Mode=TwoWay}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="listBox2" Grid.Column="1" Width="300" Height="300"
VerticalAlignment="Top"
HorizontalAlignment="Left"
ItemsSource="{Binding h2hList}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding date, Mode=TwoWay}"></TextBlock>
<TextBlock Text="{Binding result, Mode=TwoWay}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
RaisePropertyChanged("teamList");
is Wrong your propery is named 'teamsList' with an S,
change to:
RaisePropertyChanged("teamsList");
It is the public property you bind to and notify changes of,
edit:
also change your binding:
ItemsSource="{Binding teamList}"
to
ItemsSource="{Binding teamsList}"
Edit 2:
listBox2.DataContext = xxx
Not itemsource = xxx
With the line (in listBox1_SelectionChanged)
listBox2.ItemsSource = lists.h2hList;
you are effectively removing the binding from the ItemsSource property of listBox2.
Instead, you should only update the h2hList property in your Lists class (which presumably happens in getH2hResults) and remove the above line from your code.
Note however that it is not sufficient to clear and re-fill that list. You need to set the h2hList property in order to get a property change notification raised:
var newList = new List<H2H>();
// fill newList before assigning to h2hList property
lists.h2hList = newList;
If you want to keep the list and just change its elements, you would need to use ObservableCollection<H2H> instead of List<H2H> as collection type. This would be the better approach anyway, as you would not have to care for when exactly you add elements to a newly created collection.

detect selecteditem details in ListBox from MVVM app in windows phone

I have the following view.xaml and I bind a collection(SavedTracksCollection from viewmodel) to this list box and it displays the items in UI.
<phone:PanoramaItem Name="MusicTracks" Header="Saved Tracks" >
<Grid>
<ListBox x:Name="list" ItemsSource="{Binding SavedTracksCollection}" SelectedItem="{Binding SelectedItemTrack,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Background="Red" >
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding TrackTitle}"/>
<TextBlock Text="{Binding TrackUri}"/>
</StackPanel>
</Button>
<DataTemplate>
</ListBox.ItemTemplate>
</Grid>
</phone:PanoramaItem>
And the i have the following property defined in my viewmodel(this viewmodel is set as data context for my view) for the selecteditem binding "SelectedItemTrack".And i am binding SavedTracksCollection to the itemsource of the list.
private SavedTracksModel _SelectedItemTrack;
public SavedTracksModel SelectedItemTrack
{
get {
return _SelectedItemTrack;
}
set
{
if (value!=null)
_SelectedItemTrack = value;
//RaisePropertyChanged("SelectedItemTrack"); I dont think we need this.Let me know otherwise.
}
}
private List<SavedTracksModel> _SavedTracksCollection = new List<SavedTracksModel>();
public List<SavedTracksModel> SavedTracksCollection
{
get
{
return GetSavedTracks();
}
set
{
this._SavedTracksCollection = value;
RaisePropertyChanged("SavedTracksCollection");
}
}
But i am not able to determine how do i capture the SelectedITem event when user selectes an item from the Listbox .Currently it doesn't trigger the set method of the SelectedITemTrack .Once i capture the event with the details of selected item binding "TrackUri" i want to go to a new page where i can play the track.
any idea how to fix the issue ?
The first solution I can think of, why not just use the SelectionChanged event on ListBox?
<ListBox x:Name="list" ItemsSource="{Binding SavedTracksCollection}"
SelectedItem="{Binding SelectedItemTrack,Mode=TwoWay}"
SelectionChanged="List_OnSelectionChanged"/>
// in code behind
private void List_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// navigate here after validating the selected item
// or raise Command in your ViewModel programatically
}

Can I swap a buttons content databind to a different databind in code?

I cannot find any examples to make me understand how and if I can change the databind in c# at the click of a button on, in my case a toggleswitch, Basically I have 32 buttons in my app and those 32 buttons act the same but need different text with-in them depending on some toggle switches they are currently databinded so the text can be saved and retrieved from local storage but what values it gets depends on the state of these toggle switches.
So I currently have :
<Button x:Name="_ovButton1" Content="{Binding Source={StaticResource AppSettings}, Path=ovName1_1Value, Mode=TwoWay}" Margin="2,0,250,0" VerticalAlignment="Top" FontSize="14" Height="72" FontWeight="Bold" MouseLeftButtonUp="_ovButton1_MouseLeftButtonUp" MouseLeftButtonDown="_ovButton1_MouseLeftButtonDown" ClickMode="Hover" Hold="_ovButton1_Hold"/>
and I want when a user changes the state of a toggleswitch to change the
{StaticResource AppSettings}, Path=ovName1_1Value, Mode=TwoWay}
to for example:
{StaticResource AppSettings}, Path=ovName1_2Value, Mode=TwoWay}
but I cannot find any example that shows how to do that in c#
what code do I need to do that?
You can specify the target of databinding in code like this:
MyData myDataObject = new MyData(DateTime.Now);
Binding myBinding = new Binding("MyDataProperty");
myBinding.Source = myDataObject;
myText.SetBinding(TextBlock.TextProperty, myBinding);
See more at http://msdn.microsoft.com/en-us/library/ms742863.aspx
-- Edit Note I don't have access to a WP8 Emulator to test this ---
In the view model it looks like this:
public List<string> Members
{
get { return _Members; }
set { _Members = value; OnPropertyChanged(); }
}
public MainVM()
{
// Simulate Asychronous access, such as to a db.
Task.Run(() =>
{
Thread.Sleep(2000);
Members = new List<string>() {"Alpha", "Beta", "Gamma", "Omega"};
});
}
The code behind on the main page sets the datacontext (shared with all the child controls) as such:
public MainWindow()
{
InitializeComponent();
// Set the windows data context so all controls can have it.
DataContext = new MainVM();
}
The Mainpage Xaml to bind to members is like this
<Button Height="30"
Width="80"
Margin="10"
DataContext="{Binding Members}"
Content="{Binding Path=[0] }" />
<Button Height="30"
Width="80"
Margin="10"
DataContext="{Binding Members}"
Content="{Binding Path=[1] }" />
<Button Height="30"
Width="80"
Margin="10"
DataContext="{Binding Members}"
Content="{Binding Path=[2] }" />
<Button Height="30"
Width="80"
Margin="10"
DataContext="{Binding Members}"
Content="{Binding Path=[3] }" />
The result is this visually:
I based this on my blog article Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding for more info and a fuller example.
I think your best bet is going to be to use a collection of strings and bind to that collection. You can either change the collection when a toggle is switched, or keep 6 collections and bind to the collection that is for the toggle.
Xaml:
<ItemsControl x:Name="Buttons" ItemsSource="{Binding ButtonTextCollection}">
<ItemsControl.ItemsPanel>
<toolkit:WrapPanel/>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="100" Height="70" Content="{Binding}" Click="OnButtonClick"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Your code-behind would have the event handler for your button click
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var text = ((Button) sender).Content.ToString();
// Send the text
}
Your ViewModel would hold the ButtonTextCollection property and would change based on the toggle.
public ICollection<string> ButtonTextCollection
{
get { return _buttonTextCollection; }
set
{
_buttonTextCollection = value;
OnPropertyChanged("ButtonTextCollection");
}
}
When you want to change the text, you would change the ButtonTextCollection
public void ChangeButtonText()
{
ButtonTextCollection = new Collection<string> {"A", "B",...};
}

Categories

Resources