I am trying to update the list which is Bound to ListBox , When the scroll bar reaches end.I need to update the list and show the changes in UI also.Here it is not updating automatically.Can someone please help me in fulfilling my requirement.
If i tried to use TwoWay mode, It shows below error:
Error : Invalid binding path 'itemsList' : Cannot bind type 'System.Collections.Generic.List(System.String)' to 'System.Object' without a converter
<ScrollViewer
x:Name="sv"
ViewChanged="OnScrollViewerViewChanged">
<ListBox x:Name="listView"
HorizontalAlignment="Left"
Height="Auto"
VerticalAlignment="Top"
Width="172"
ItemsSource="{x:Bind itemsList, Mode=OneWay}"/>
</ScrollViewer>
and the code
public List<String> itemsList = new List<string>();
private void OnScrollViewerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var verticalOffset = sv.VerticalOffset;
var maxVerticalOffset = sv.ScrollableHeight; //sv.ExtentHeight - sv.ViewportHeight;
if (maxVerticalOffset < 0 ||
verticalOffset == maxVerticalOffset)
{
// Scrolled to bottom
Util.debugLog("REACHED BOTTOM");
int i;
// itemsList = null;
itemsList.Clear();
for (i = 0; i < 20; i++)
{
itemsList.Add("Item number " + i + 900);
}
}
else
{
// Not scrolled to bottom
// rect.Fill = new SolidColorBrush(Colors.Yellow);
}
}
Here(In below link) is the answer for my question.Thanks alot for all who tried to answer my question.
https://social.technet.microsoft.com/Forums/en-US/7c730558-f933-4483-8d5b-1710d19f99de/xbind-in-windows-10-mode-one-way-i-am-trying-to-update-the-bind-list-when-scrollview-reached-to?forum=wpf
Related
Looking forward to your assistance once again :)
I'm trying to have the buttons on the far right be able to delete their row in the tableview control. Right now they now about which row they are on but I cannot connect this information to the parent. The table view is populated with a custom viewcell.
The custom view cell contains two different pickers, two entry fields and a button. I haven't found a cleaner way to execute this as I have the picker's data which isn't related to the # of rows in the data table control.
Currently when you click a button on the right it posts to the console what row was selected but I don't know of a way to connect that to its parent in order to actually delete that row on the data table
View Cell Code Behind
public partial class RecipeIngredientViewCell : ViewCell
{
ObservableCollection<clIngredient> _listIngredients = new ObservableCollection<clIngredient>();
public ObservableCollection<clIngredient> listIngredients { get { return _listIngredients; } }
ObservableCollection<clUnit> _listUnit = new ObservableCollection<clUnit>();
public ObservableCollection<clUnit> funclistUnit { get { return _listUnit; } }
clRecipeIngredient _recipeIngredient;
int _row;
public RecipeIngredientViewCell(clRecipeIngredient passedrecipeIngredient, ObservableCollection<clIngredient> passedlistIngredients, ObservableCollection<clUnit> passedlistUnits, int row)
{
InitializeComponent();
_listIngredients = passedlistIngredients;
_listUnit = passedlistUnits;
_recipeIngredient = passedrecipeIngredient;
_row = row;
this.BindingContext = _recipeIngredient;
//INGREDIENT PICKER
pickerIngredient.ItemsSource = _listIngredients;
for(int x = 0; x < _listIngredients.Count; x++)
{
if (_listIngredients[x].IngredientName == _recipeIngredient.IngredientName)
{
pickerIngredient.SelectedIndex = x;
}
}
//UNIT PICKER
pickerUnit.ItemsSource = _listUnit;
for (int x = 0; x < _listUnit.Count; x++)
{
if (_listUnit[x].UnitName == _recipeIngredient.UnitName)
{
pickerUnit.SelectedIndex = x;
}
}
}
private void btnDeleteRecipeIngredient_Clicked(object sender, EventArgs e)
{
//NOT IMPLEMENTED YET!
Console.WriteLine(_recipeIngredient.IngredientName + " AT ROW " + _row.ToString());
}
private void txtQuantity_TextChanged(object sender, TextChangedEventArgs e)
{
_recipeIngredient.Quantity = txtQuantity.Text.ToDouble();
}
private void txtComment_TextChanged(object sender, TextChangedEventArgs e)
{
_recipeIngredient.Comments = txtComment.Text;
}
private void pickerIngredient_SelectedIndexChanged(object sender, EventArgs e)
{
_recipeIngredient.IngredientName = pickerIngredient.SelectedItem.ToString();
}
private void pickerUnit_SelectedIndexChanged(object sender, EventArgs e)
{
_recipeIngredient.UnitName = pickerIngredient.SelectedItem.ToString();
}
}
View Cell XAML
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="RecipeDatabaseXamarin.Views.RecipeIngredientViewCell">
<Grid VerticalOptions="CenterAndExpand" Padding = "20, 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Picker Grid.Column = "0" x:Name="pickerIngredient" HorizontalOptions = "StartAndExpand" SelectedIndexChanged="pickerIngredient_SelectedIndexChanged"/>
<Entry Grid.Column = "1" x:Name ="txtQuantity" HorizontalOptions = "StartAndExpand" Text = "{Binding Quantity}" TextChanged="txtQuantity_TextChanged" />
<Picker Grid.Column = "2" x:Name ="pickerUnit" HorizontalOptions = "StartAndExpand" SelectedIndexChanged="pickerUnit_SelectedIndexChanged"/>
<Entry Grid.Column = "3" x:Name="txtComment" HorizontalOptions = "StartAndExpand" Text = "{Binding Comments}" TextChanged="txtComment_TextChanged" WidthRequest="150"/>
<Button Grid.Column = "4" x:Name="btnDeleteRecipeIngredient" HorizontalOptions = "StartAndExpand" Text = "Delete Ingredient" Clicked="btnDeleteRecipeIngredient_Clicked"/>
</Grid>
Code Behind for Page
var section = new TableSection();
for(int i = 0;i<_downloadedRecipeIngredients.Count;i++)
{
var cell = new RecipeIngredientViewCell(downloadedRecipeIngredients[i], listIngredients, listUnit, i);
section.Add(cell);
}
tblData.Root.Add(section);
In the main page code behind I want the button to run a block of code to execute something such as
tblData.Root.del(ROW_INDEX);
Thanks!
I believe I have this solved. Will post the solution when I get back from the 4th weekend.
The solution to this problem is answered on another post. Basically the solution is easier once MVVM is implemented even though it was a pain to get it to work on the picker withing the listView control.
This other thread has sample code which you can run.
Trying to set picker within listview MVVM Xamarin
If anyone runs into the same issue please post and I'll try to respond back as this issue was a PAIN!!!!
I am not a notorious xamarin programmer, but you have your width to auto, which most likely changes the whole grid the moment the width changes. Therefore it will align the buttons differently too.
It seems you could position the horizontalOptions to "End" to at least put the buttons to the end of the screen. If you want to have it always the same, I would give them a certain width per section.
I'm trying to use a ListBox to choose an entry and then display a picture belonging to this selected entry. But just at the beginning I got my first problem: filling the ListBox with binding is working, but if I click on one line in my running program, it doesn't select the line. I can just see the highlighted hover effect, but not select a line. Any ideas what my mistake could be?
This is my XAML:
<ListBox x:Name="entrySelection" ItemsSource="{Binding Path=entryItems}" HorizontalAlignment="Left" Height="335" Margin="428,349,0,0" VerticalAlignment="Top" Width="540" FontSize="24"/>
And in MainWindow.xaml.cs I'm filling the ListBox with entries:
private void fillEntrySelectionListBox()
{
//Fill listBox with entries for active user
DataContext = this;
entryItems = new ObservableCollection<ComboBoxItem>();
foreach (HistoryEntry h in activeUser.History)
{
var cbItem = new ComboBoxItem();
cbItem.Content = h.toString();
entryItems.Add(cbItem);
}
this.entrySelection.ItemsSource = entryItems;
labelEntrySelection.Text = "Einträge für: " + activeUser.Id;
//show image matching the selected entry
if (activeUser.History != null)
{
int index = entrySelection.SelectedIndex;
if (index != -1 && index < activeUser.History.Count)
{
this.entryImage.Source = activeUser.History[index].Image;
}
}
}
So I can see my ListBox correctly filled, but not select anything - so I can't go on with loading the picture matching the selected entry.
I'm still quite new to programming, so any help would be great :)
EDIT: If someone takes a look at this thread later: here's the - quite obvious -solution
XAML now looks like this
<ListBox x:Name="entrySelection" ItemsSource="{Binding Path=entryItems}" HorizontalAlignment="Left" Height="335" Margin="428,349,0,0" VerticalAlignment="Top" Width="540" FontFamily="Siemens sans" FontSize="24">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind to fill it:
//Fill listbox with entries for selected user
DataContext = this;
entryItems = new ObservableCollection<DataItem>();
foreach (HistoryEntry h in selectedUser.History)
{
var lbItem = new DataItem(h.toString());
entryItems.Add(lbItem);
}
this.entrySelection.ItemsSource = entryItems;
labelEntrySelection.Text = "Einträge für: " + selectedUser.Id;
And new Class DataItem:
class DataItem
{
private String text;
public DataItem(String s)
{
text = s;
}
public String Text
{
get
{
return text;
}
}
}
You are filling it with ComboBoxItem, which is not relevant to the ListBox, and also wrong by definition.
You need to have the ObservableCollection filled with data items.
Meaning, make a class that contains the data you want to store, and the ListBox will generate a ListBoxItem automatically per data item.
http://www.wpf-tutorial.com/list-controls/listbox-control/
Oxyplot graphs 13 points which are derived from the 6 user input text boxes. The values in the text boxes are held in public variables in the MainWindow.xaml.cs class. The variables are updated when the user presses enter in the text box. How would I make the refresh button refresh the graph.
private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
//Refresh The Graph
}
I think that this would be done using the
PlotModel.RefreshPlot()
method, but I am not sure how to implement it because of Oxyplot's poor documentation.
I just updated to a new version of OxyPlot via NuGet. I'm using OxyPlot.Wpf v20014.1.277.1 and I think you now need to call InvalidatePlot(bool updateData) on the PlotModel instead of RefreshPlot (which is no longer available). I tested this in my sample code and it worked as expected.
If you want to refresh the plot and update the data collections, you need to pass true to the call:
PlotModel.InvalidatePlot(true)
Give x:Name to OxyPlot instance in XAML:
<oxy:Plot x:Name="Plot1"/>
and on button click handler, refresh like this:
private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
Plot1.RefreshPlot(true);
}
The cleanest way I've found to get "sort of" auto-update is reacting to CollectionChanged on the collection that is LineSeries' ItemsSource.
In ViewModel:
ObservableCollection<DataPoint> Data { get; set; }
= new ObservableCollection<DataPoint>();
public PlotModel PlotModel
{
get { return _plot_model; }
set
{
_plot_model = value;
RaisePropertyChanged(() => PlotModel);
}
}
PlotModel _plot_model;
// Inside constructor:
Data.CollectionChanged += (a, b) => PlotModel.InvalidatePlot(true);
In the current OxyPlot.Wpf (1.0.0-unstable1983) you have two options:
Bind the Series.ItemsSource property from XAML to a collection in your viewmodel and exchange the whole collection, when you need an update. This also allows for concurrent async updates with larger data sets.
Bind the Plot.InvalidateFlag property of type int to your viewmodel and increment whenever you need an update. I haven't tested this approach, though.
The following code illustrates both options (pick one). XAML:
<oxy:Plot InvalidateFlag="{Binding InvalidateFlag}">
<oxy:Plot.Series>
<oxy:LineSeries ItemsSource="{Binding DataSeries}" />
</oxy:Plot.Series>
</oxy:Plot>
Updates on the ViewModel:
private async Task UpdateAsync()
{
// TODO do some heavy computation here
List<DataPoint> data = await ...
// option 1: Trigger INotifyPropertyChanged on the ItemsSource.
// Concurrent access is ok here.
this.DataSeries = data; // switch data sets
// option 2: Update the data in place and trigger via flag
// Only one update at a time.
this.DataSeries.Clear();
data.ForEach(this.DataSeries.Add);
this.InvalidateFlag++;
}
After having the same question with the same issue, it would seem that the only working solution (at least to my point of view) is as followed :
PlotView.InvalidatePlot(true)
Doing so, after updating one or multple Series do refresh your PlotView.
The refresh rate depends on how often, or at which rate your serie(s) is/are updated.
Here is a code snippet (on Xamarin Android but should work anyway) :
PlotView resultsChart = FindViewById<PlotView>(Resource.Id.resultsChart);
PlotModel plotModel = new PlotModel
{
// set here main properties such as the legend, the title, etc. example :
Title = "My Awesome Real-Time Updated Chart",
TitleHorizontalAlignment = TitleHorizontalAlignment.CenteredWithinPlotArea,
LegendTitle = "I am a Legend",
LegendOrientation = LegendOrientation.Horizontal,
LegendPlacement = LegendPlacement.Inside,
LegendPosition = LegendPosition.TopRight
// there are many other properties you can set here
}
// now let's define X and Y axis for the plot model
LinearAxis xAxis = new LinearAxis();
xAxis.Position = AxisPosition.Bottom;
xAxis.Title = "Time (hours)";
LinearAxis yAxis = new LinearAxis();
yAxis.Position = AxisPosition.Left;
yAxis.Title = "Values";
plotModel.Axes.Add(xAxis);
plotModel.Axes.Add(yAxis);
// Finally let's define a LineSerie
LineSeries lineSerie = new LineSeries
{
StrokeThickness = 2,
CanTrackerInterpolatePoints = false,
Title = "Value",
Smooth = false
};
plotModel.Series.Add(lineSerie);
resultsChart.Model = plotModel;
Now, whenever you need to add DataPoints to your LineSerie and to updated automatically the PlotView accordingly, just do as followed :
resultsChart.InvalidatePlot(true);
Doing so will automatically refresh your PlotView.
On a side note, the PlotView will also be updated when an event occurs such as a touch, a pinch to zoom, or any kind of UI-related events.
I hope I could help. I had trouble with this for a very long time.
Exists three alternatives how refresh plot (from OxyPlot documentation):
Change the Model property of the PlotView control
Call Invalidate on the PlotView control
Call Invalidate on the PlotModel
Another two years later... this solution works for me, because I have no oxyplot models and I´m missing some of the named functions from above.
code behind:
public partial class LineChart : UserControl
{
public LineChart()
{
InitializeComponent();
DataContext = this;
myChart.Title = "hier könnte Ihr Text stehen!";
this.Points = new List<DataPoint>();
randomPoints();
}
public IList<DataPoint> Points { get; private set; }
public void randomPoints()
{
Random rd = new Random();
String myText = "";
int anz = rd.Next(30, 60);
for (int i = 0; i < anz; i++)
myText += i + "," + rd.Next(0, 99) + ";";
myText = myText.Substring(0, myText.Length - 1);
String[] splitText = myText.Split(';');
for (int i = 0; i < splitText.Length; i++)
{
String[] tmp = splitText[i].Split(',');
Points.Add(new DataPoint(Double.Parse(tmp[0].Trim()), Double.Parse(tmp[1].Trim())));
}
while (Points.Count > anz)
Points.RemoveAt(0);
myChart.InvalidatePlot(true);
}
}
To update your data don't exchange the whole IList, rather add some new DataPoints to it and remove old ones at position 0.
XAML:
<UserControl x:Class="UxHMI.LineChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UxHMI"
xmlns:oxy="http://oxyplot.org/wpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="Container" Background="White">
<oxy:Plot x:Name="myChart" Title="{Binding Title}" FontFamily="Bosch Sans Medium" Foreground="#FF0C6596" FontSize="19" Canvas.Left="298" Canvas.Top="32" Background="AliceBlue" Margin="0,0,10,0">
<oxy:Plot.Series>
<oxy:LineSeries x:Name="ls" Background="White" ItemsSource="{Binding Points}" LineStyle="Solid" Color="ForestGreen" MarkerType="None" MarkerSize="5" MarkerFill="Black">
</oxy:LineSeries>
</oxy:Plot.Series>
</oxy:Plot>
<Button x:Name="button" Content="Random" HorizontalAlignment="Left" Margin="0,278,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
important are the x:Name="myChart" and ItemsSource="{Binding Points}"
I hope this is useful for someone out there
I have a ListBox which contains a couple of TextBlocks, an Image, and at least 2 TextBoxs. However my problem is that I need to be able to retrieve all the TextBox(s) in the ListBox; APART FROM THE FIRST ONE, and then assign them to a List in C#.
Here is the ListBox in .xaml:
<ListBox Margin="0,-20,0,0" Height="548" Name="listBoxNew">
<TextBlock Name="textBlockName" Text="Name"/>
<TextBox Name="textBoxName" Width="420" Margin="-12,0,0,0"/>
<TextBlock Name="textBlockAdd" Text="Add" Margin="0,10,0,0"/>
<TextBox Name="textBoxAdd" Width="420" Margin="-12,0,0,0"/>
<Image Name="imageAdd" Source="/SecondApp%2b;component/Images/buttonAdd1.png"
Height="50" Margin="0,5,0,0" Tap="imageAdd_Tap"
toolkit:TiltEffect.IsTiltEnabled="True"
ManipulationStarted="imageAddExersize_ManipulationStarted"
ManipulationCompleted="imageAddExersize_ManipulationCompleted" />
</ListBox>
The ListBox may have more TextBoxs than shown in .xaml, as the user can create more by tapping on the Image.
Thank alot, all help is appreciated.
You can do it very simply using Linq. Following sentence returns all the elements from the ListBox of type TextBox except the first one:
var textBoxList = listBoxNew.Items.Where(x => x.GetType() == typeof(TextBox)).Skip(1).ToList();
Remember you have to add using System.Linq; to your file.
hello #Newbie i have solution for you..i know it is not optimized one..but it is working for your case..
i am comparing the types..here ( by not good way) ..i ma doing on a buttonclick..
List<object> lstobj;
private void Button_Click_2(object sender, RoutedEventArgs e)
{
int t = listBoxNew.Items.Count();
lstobj = new List<object>();
TextBox obj = new TextBox();
int p = 0;
for (int i = 0; i < t; i++)
{
if(listBoxNew.Items[i].GetType()==obj.GetType())
{
if (p == 0)
{
p = 1;
continue;
}
else
{
lstobj.Add(listBoxNew.Items[i]);
}
}
}
}
hope it helps you..
I have a Panorama control where i need to programmaticaly add items which are images.
I want to implement them so that flicking on the image slide to second image and so on..
I did add images to the panaroma item but it always shows one image only.
for (int i = 0; i < 10; i++)
{
image_new = new Image();
PanoramaItem pi = new PanoramaItem();
image_new.Source = "Some image Bitmap";
pi.Content = image_new;
image_panaroma.Items.Add(pi);
}
xaml layout is :
<Grid x:Name="LayoutRoot">
<controls:Panorama Name="image_panaroma">
</controls:Panorama>
</Grid>
Can someone tell me what is wrong?
Also is there any other way possible to give sliding transition to images?
You don't say what exception you get, but I think a better approach would be to create an ItemTemplate for the Panorama control and bind it to your list of objects.
public class ItemData
{
public string Name { get; set; }
public string Path { get; set; }
}
...
List<ItemData> items = new List<ItemData>(10);
for (int i = 0; i < 10; i++)
{
items.Add(new ItemData { Name = "Something", Path = "Image path" });
}
this.image_panorama.ItemsSource = items;
Your XAML would look something like this:
<controls:Panorama x:Name="image_panorama">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}" />
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
You say that this only shows 1 image. Is this the same image 10 times (one for each pivotItem) or is only 1 pivotItem being created?
If it's the first then it could be how you're creating the image and/or setting the source.
Your example code doesn't show that you're using a different image source or how image_new is scoped. Without a more complete example of your actual code it's hard to say for sure.
The following will (works-on-my-machine) create 10 items all with the same image:
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
for (var i = 0; i < 10; i++)
{
var image_new = new Image();
var pi = new PanoramaItem();
var bi = new BitmapImage(new Uri("/Background.png", UriKind.Relative));
image_new.Source = bi;
pi.Content = image_new;
image_panaroma.Items.Add(pi);
}
}
Are you using the January Update? (I am-see above for WOMM disclaimer) This update includes changes that affect the panorama control.