syncfusion chart does not display data - mvvm

I added SFchart, it had no errors and it compiles. It shows an empty chartview.
I'm using MVVMcross in Xamarin.IOS
The data I requested is there, it contains about 200 rows, the data is requested from my api with the method override void viewAppearing.
My view in viewdidload:
//Initialize the Chart with required frame. This frame can be any rectangle, which bounds inside the view.
SFChart chart = new SFChart();
chart.Frame = this.headerView.Frame;
//Adding Primary Axis for the Chart.
SFCategoryAxis primaryAxis = new SFCategoryAxis();
chart.PrimaryAxis = primaryAxis;
//Adding Secondary Axis for the Chart.
SFNumericalAxis secondaryAxis = new SFNumericalAxis();
chart.SecondaryAxis = secondaryAxis;
chart.Series.Add(new SFColumnSeries()
{
ItemsSource = (this.ViewModel as UserCoinViewModel).CoinHistory,
XBindingPath = "price_btc",
YBindingPath = "timestamp"
});
this.View.AddSubview(chart);
viewmodel:
private List<CoinHistoryModel> _CoinHistory;
public List<CoinHistoryModel> CoinHistory
{
get
{
return _CoinHistory;
}
set
{
_CoinHistory = value;
RaisePropertyChanged(() => CoinHistory);
}
}

Because you are using MVVMcross, you should use bind method to set your Series's ItemsSource. You just set the ItemsSource to the viewModel instance's property, when the value changed it will not notify the View. So it seems to show an empty chart.
Modify your code to bind like:
SFColumnSeries series = new SFColumnSeries()
{
XBindingPath = "price_btc",
YBindingPath = "timestamp"
};
chart.Series.Add(series);
var set = this.CreateBindingSet<YourView, UserCoinViewModel>();
...
set.Bind(series).For(s => s.ItemsSource).To(vm => vm.CoinHistory);
...
set.Apply();
Then in your ViewModel, create a command like:
private MvxCommand loadDataCommand;
public ICommand LoadDataCommand
{
get
{
return loadDataCommand ?? (loadDataCommand = new MvxCommand(ExecuteloadDataCommand));
}
}
private void ExecuteloadDataCommand()
{
CoinHistory = new List<CoinHistoryModel>()
{
new CoinHistoryModel{ price_btc = "First", timestamp = 10 },
new CoinHistoryModel{ price_btc = "Second", timestamp = 20 },
new CoinHistoryModel{ price_btc = "Third", timestamp = 30 }
};
// Change it to your data request here
}
At last trigger this command in your ViewWillAppear() event:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
(ViewModel as UserCoinViewModel).LoadDataCommand.Execute(null);
// You can also bind a button to this command to trigger it manually.
}

Related

How can i make Http request again in retrofit to get updated data from api

I want to update the data I'm getting from api to display it in my lazy column, I'm trying to add swipe down to refresh functionality.
I'm getting the data from my viewmodel
#HiltViewModel
class MatchesViewModel #Inject constructor(
private val matchRepository: MatchRepository
): ViewModel() {
val response: MutableState<ApiState> = mutableStateOf(ApiState.Empty)
init {
getAllMatches()
}
private fun getAllMatches() = viewModelScope.launch {
cricketRepository.getAllMatches().onStart {
response.value = ApiState.Loading
} .catch {
response.value = ApiState.Failure(it)
}.collect {
response.value = ApiState.Success(it) }
}
}
then i made new kotlin file where I'm checking if I'm getting the data and passing it in my lazy column
#Composable
fun MainScreen(viewModel: MatchesViewModel = hiltViewModel()){
when (val result = viewModel.response.value){
is ApiState.Success -> {
HomeScreen(matches = result.data.data)
}
is ApiState.Loading -> {
}
is ApiState.Empty -> {
}
is ApiState.Failure -> {
}
}
}
i want to know how can i make the request again to get the updated data
after some googling i found out you can retry api calls with okhttp interceptors but could'nt find any documentation or tutorial to retry calls with interceptor
You can try Swipe to Refresh with the accompanist dependencie
implementation "com.google.accompanist:accompanist-swiperefresh:0.26.5-rc"
Implementation would be like this
val swipeRefreshState = rememberSwipeRefreshState(false)
SwipeRefresh(
state = swipeRefreshState,
onRefresh = {
swipeRefreshState.isRefreshing = false
viewModel.<FUNCTION TO LOAD YOUR DATA>
},
indicator = { swipeRefreshState, trigger ->
SwipeRefreshIndicator(
// Pass the SwipeRefreshState + trigger through
state = swipeRefreshState,
refreshTriggerDistance = trigger,
// Enable the scale animation
scale = true,
// Change the color and shape
backgroundColor = <UPDATE CIRLE COLOR>,
contentColor = <RELOADING ICON COLOR>,
shape = RoundedCornerShape(50),
)
}
) {
<CONTENT OF YOUR SCREEN>
}

How to update list view from another class in Xamarin forms?

I have created a list view in one class and called delete method from another class. Listview getting call but not updating list view if i call from another class. But its getting update when i call inside the same class. How to solve this issue?
namespace New
{
public partial class WishesPage : ContentPage
{
ListView listView = new ListView();
public WishesPage()
{
InitializeComponent();
var arr = JToken.Parse(ids);
foreach (var ite in arr.Children())
{
var itemProperties = ite.Children<JProperty>();
string contactElement = itemProperties.FirstOrDefault(x => x.Name == "contact").Value.ToString();
sample.Add(contactElement);
}
listView.ItemTemplate = new DataTemplate(typeof(CustomListCell));
listView.ItemsSource = sample;
Content = new StackLayout
{
Children =
{
listView,
}
};
}
public async Task delete(string wishid)
{
indicator.IsRunning = true;
var client = new HttpClient();
client.BaseAddress = new Uri("http:……”);
if (response == "success")
{
listView.ItemsSource = null;
listView.ItemsSource = sample;
}
}
}
public class CustomListCell : ViewCell
{
public CustomListCell()
{
wishIdLabel.SetBinding(Label.TextProperty, new Binding("contact"));
horizontalLayout.Children.Add(wishIdLabel);
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true };
deleteAction.Clicked += async (sender, e) =>
{
WishesPage wishes = new WishesPage();
wishes.delete(wishId);
};
ContextActions.Add(deleteAction);
}
}
}
I have updated this repo that explain how to use Commands inside a ViewCell.
In your case, you should move the construction of ViewCell inside the ContentPage. Something like
lv.ItemTemplate = new DataTemplate(() =>
{
StackLayout slView = new StackLayout();
Label lDesc = new Label();
lDesc.SetBinding(Label.TextProperty, "Description", stringFormat: "DESCRIPTION: {0}");
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.SetBinding(MenuItem.CommandProperty, new Binding("BindingContext.TrashCommand", source: this));
deleteAction.SetBinding(MenuItem.CommandParameterProperty, ".");
slView.Children.Add(lDesc);
ViewCell vc = new ViewCell() {View = slView };
vc.ContextActions.Add(deleteAction);
return vc;
}
Now, when you longpress the row, a ContextAction "Delete" appears and a TrashCommand in your ViewModel is executed (you should use MVVM...), a "these" parameter is passed (the selected obj) so you can delete it from the List
this.TrashCommand = new Command(async (object obj) => {
try
{
if (_isTapped)
return;
if (obj != null)
System.Diagnostics.Debug.WriteLine("Obj is not null");
else
System.Diagnostics.Debug.WriteLine("Obj IS null");
_isTapped = true;
var ret = await Application.Current.MainPage.DisplayAlert("Attention", "Delete this row?", "Yes", "No");
if (ret)
{
// List is your "sample" list... Removing the obj, is it reflected to ListView if you use ObservableCollection instead of List
List.Remove((Model)obj);
Count = List.Count;
}
_isTapped = false;
}
catch (Exception ex) {
_isTapped = false;
await Application.Current.MainPage.DisplayAlert("Attention", ex.Message, "Ok");
}
});
}

Custome Formatter within a Controller - SAPUI5

I'm trying to format gender field (in SAP table field: CHAR1 to 0(F) and 1(M) to fit the selectedIndex property of RadioButtonGroup.
This is my view : (DetailDialog.fragment.xml )
<RadioButtonGroup width="100%" columns="2" selectedIndex="{path: 'Gendr', formatter:'.formatter' }" id="__group1">
The above XML Fragment is called by the main view controller:
ItemPress: function(oEvent) {
var detailDialog = this.getView().byId("DetailDialog");
var that = this;
var view = this.getView();
var path = oEvent.getParameter("listItem").getBindingContext().getPath();
var oDummyController = {
formatter: function(gendr) {
switch (gendr) {
case "M":
return 0;
case "F":
return 1;
}
},
closeDialog: function() {
detailDialog.close();
}
};
if (!detailDialog) {
detailDialog = sap.ui.xmlfragment(view.getId(), "Demo1.view.DetailDialog", oDummyController);
}
var jSonModel = new sap.ui.model.json.JSONModel();
function fnSuccess(oData, oResponse) {
jSonModel.setData(oData);
}
var oModel = view.getModel();
oModel.read(path, {
success: fnSuccess
})
//Set data for dialog
this.getView().byId("__formDetail").setModel(jSonModel);
detailDialog.open();
}
My problem is that the formatter is not working at all.
Any suggestion?
Option one: (not sure if it works for fragments too)
Change formatter:'.formatter' to formatter:'Demo1.view.DetailDialog.formatter'.
Option two: Format the data since anyway you are binding data from controller. (And surely will work.)
function fnSuccess(oData, oResponse) {
oData.GendrValue = oData.Gendr == "M"?1:0;
jSonModel.setData(oData);
}
and also change the binding: selectedIndex="{path: 'GendrValue'}"

Property Triggers is not working in the code-behind

I am using Xamarin.Forms in which i have used property triggers behind the code all coding is been done .Please help me out what mistake i did in the code.
Label header = new Label
{
Text = "Trigger",
Font = Font.BoldSystemFontOfSize(50),
HorizontalOptions = LayoutOptions.Center
};
Entry enter = new Entry
{
Placeholder = "Enter Name"
};
Trigger trigger = new Trigger(typeof(Entry))
{
Property = Entry.IsFocusedProperty,
Value = "True"
};
trigger.Setters.Add(new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.Red
});
enter.Triggers.Add(trigger);
this.Content = new StackLayout
{
Children =
{
header,
enter
}
};
Only Trigger part is not working

Merge Self-tracking entities

Graph of objects stored in the database and the same object graph is serialized into a binary package. Package is transmitted over the network to the client, then it is necessary to merge data from the package and data from the database.
Source code of merge:
//objList - data from package
var objectIds = objList.Select(row => row.ObjectId).ToArray();
//result - data from Database
var result = SomeService.Instance.LoadObjects(objectIds);
foreach (var OSobj in objList)
{
var obj = result.Objects.ContainsKey(OSobj.ObjectId)
? result.Objects[OSobj.ObjectId]
: result.Objects.CreateNew(OSobj.ObjectId);
var targetObject = result.DataObjects.Where(x => x.ObjectId == OSobj.ObjectId).FirstOrDefault();
targetObject.StopTracking();
var importedProperties = ImportProperties(targetObject.Properties, OSobj.Properties);
targetObject.Properties.Clear();
foreach (var property in importedProperties)
{
targetObject.Properties.Add(property);
}
targetObject.StartTracking();
}
return result;
And code of ImportProperties method:
static List<Properties> ImportProperties(
IEnumerable<Properties> targetProperties,
IEnumerable<Properties> sourceProperties)
{
Func<Guid, bool> hasElement = targetProperties
.ToDictionary(e => e.PropertyId, e => e)
.ContainsKey;
var tempTargetProperties = new List<Properties>();
foreach (var sourceProperty in sourceProperties)
{
if (!hasElement(sourceProperty.PropertyId))
{
sourceProperty.AcceptChanges();
tempTargetProperties.Add(sourceProperty.MarkAsAdded());
}
else
{
sourceProperty.AcceptChanges();
tempTargetProperties.Add(sourceProperty.MarkAsModified());
}
}
return tempTargetProperties;
}
Server save incoming changes like this :
_context.ApplyChanges("OSEntities.Objects", entity);
_context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
When the server tries to save the changes occur exception:
AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
But if I change the code of ImportProperties method, the error does not occur and the changes are saved successfully:
static List<Properties> ImportProperties(
IEnumerable<Properties> targetProperties,
IEnumerable<Properties> sourceProperties)
{
Func<Guid, bool> hasElement = targetProperties.ToDictionary(e => e.PropertyId, e => e).ContainsKey;
var tempTargetProperties = new List<Properties>();
foreach (var sourceProperty in sourceProperties)
{
if (!hasElement(sourceProperty.PropertyId))
{
var newProp = new Properties
{
ElementId = sourceProperty.ElementId,
Name = sourceProperty.Name,
ObjectId = sourceProperty.ObjectId,
PropertyId = sourceProperty.PropertyId,
Value = sourceProperty.Value
};
tempTargetProperties.Add(newProp);
}
else
{
var modifiedProp = new Properties
{
ElementId = sourceProperty.ElementId,
Name = sourceProperty.Name,
ObjectId = sourceProperty.ObjectId,
PropertyId = sourceProperty.PropertyId,
Value = sourceProperty.Value
};
modifiedProp.MarkAsModified();
tempTargetProperties.Add(modifiedProp);
}
}
return tempTargetProperties;
}
Why is there an exception?
When you transport an object graph (Entity with n-level deep navigation properties) to a client application the entities will record any changes made in their respective change trackers. When entity (or object graph) is sent back to the server side of the application basically all you need to do is:
try
{
using(Entities context = new Entities())
{
context.ApplyChanges(someEntity);
context.SaveChanges();
}
}
catch
{
...
}
I don't see the need of all the code above you posted. What are you trying to achieve with that code?