GridView: Get Index on Drop Event - xaml

How do I get the index or position where a GridViewItem is being dropped inside the OnDrop event of the GridView? As I have read around that it is possible with GridView.ItemContainerGenerator.ContainerFromItem(item) but for me ItemContainerGenerator is null.
This is my current code:
void gridMain_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var item = e.Items.First();
var source = sender;
e.Data.Properties.Add("item", item);
e.Data.Properties.Add("source", sender);
}
void gridMain_Drop(object sender, DragEventArgs e)
{
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
object source;
e.Data.Properties.TryGetValue("source", out source);
var s = ((GridView)source).ItemContainerGenerator.ContainerFromItem(item);
}
Any hint or suggestion will be really helpful.

Use GetPosition method of DragEventArgs to find the position where item was dropped and then calculate the actual index, see code snippet below for the handler. Similar question was asked here using this MSDN example as an answer (Scenario 3).
private void GridView_Drop(object sender, DragEventArgs e)
{
GridView view = sender as GridView;
// Get your data
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
//Find the position where item will be dropped in the gridview
Point pos = e.GetPosition(view.ItemsPanelRoot);
//Get the size of one of the list items
GridViewItem gvi = (GridViewItem)view.ContainerFromIndex(0);
double itemHeight = gvi.ActualHeight + gvi.Margin.Top + gvi.Margin.Bottom;
//Determine the index of the item from the item position (assumed all items are the same size)
int index = Math.Min(view.Items.Count - 1, (int)(pos.Y / itemHeight));
// Call your viewmodel with the index and your data.
}
EDIT: Please, consider this as just a prototype. I tried it and it has worked properly, but you may revise it according to your scenario (tweak delay timeout, differentiate more TaskCompletionSource at once, etc.).
The idea is to start a task after Remove action to check whether the item was only removed, or reordered.
private async void observableCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
object removedItem = e.OldItems[0];
var reorderTask = NoticeReorderAsync(removedItem);
try
{
var task = await Task.WhenAny(reorderTask, Task.Delay(100));
if (reorderTask == task)
{
// removedItem was in fact reordered
Debug.WriteLine("reordered");
}
else
{
TryCancelReorder();
// removedItem was really removed
Debug.WriteLine("removedItem");
}
}
catch (TaskCanceledException ex)
{
Debug.WriteLine("removedItem (from exception)");
}
finally
{
tcs = null;
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
object addedItem = e.NewItems[0];
bool added = NoticeAdd(addedItem);
if (added)
{
// addedItem was just added, not reordered
Debug.WriteLine("added");
}
}
}
TaskCompletionSource<object> tcs;
private void TryCancelReorder()
{
if (tcs != null)
{
tcs.TrySetCanceled();
tcs = null;
}
}
private Task NoticeReorderAsync(object removed)
{
TryCancelReorder();
tcs = new TaskCompletionSource<object>(removed);
return tcs.Task;
}
private bool NoticeAdd(object added)
{
if (tcs != null)
{
try
{
if (object.Equals(tcs.Task.AsyncState, added))
{
tcs.TrySetResult(added);
return false;
}
else
{
tcs.TrySetCanceled();
return true;
}
}
finally
{
tcs = null;
}
}
return true;
}

Related

Webform to SQL database - how to pass user.identity.name?

I have a webform built that works well, writes back to my SQL database, but now I need to track the user id of the person who made the change. I am a SQL developer, so am a little out of my knowledge range here.
My .aspx file has
<InsertParameters>
.....
<asp:Parameter Name="StaffId" Type="String" DefaultValue= "Anonymous"/>
and my .aspx.cs file looks like this:
public partial class _BLAHBLAHBLAH_Topic1 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["UserPermission"] = null;
string username = User.Identity.Name;
if (username.StartsWith("ABC\\"))
username = username.Remove(0, 4);
bool[] userPermssion = GetUserPermissions(username);
if(!userPermssion[0])
{
ASPxGridView1.Visible = false;
WarningLabel.Visible = true;
}
}
}
private bool[] GetUserPermissions(string username)
{
bool canView = false;
bool canUpdate = false;
bool canDelete = false;
bool canInsert = false;
try
{
PermissionDataSet.UserPermissionsDataTable userDataTable = new PermissionDataSet.UserPermissionsDataTable();
PermissionDataSetTableAdapters.UserPermissionsTableAdapter adapter = new PermissionDataSetTableAdapters.UserPermissionsTableAdapter();
adapter.Fill(userDataTable, username);
if (userDataTable != null)
{
if (userDataTable.Rows.Count == 1)
{
canView = Convert.ToBoolean(userDataTable.Rows[0]["ViewFlag"]);
canUpdate = Convert.ToBoolean(userDataTable.Rows[0]["UpdateFlag"]);
canDelete = Convert.ToBoolean(userDataTable.Rows[0]["DeleteFlag"]);
canInsert = Convert.ToBoolean(userDataTable.Rows[0]["InsertFlag"]);
}
}
}
catch(Exception ex)
{
//unable to retrieve permissions - all values are defaulted to false
}
bool[] userPermission = new bool[] { canView, canUpdate, canDelete, canInsert };
Session["UserPermission"] = userPermission;
return userPermission;
}
protected void ASPxGridView1_CommandButtonInitialize(object sender, ASPxGridViewCommandButtonEventArgs e)
{
if (Session["UserPermission"] != null)
{
bool[] permission = (bool[])Session["UserPermission"];
switch (e.ButtonType)
{
case ColumnCommandButtonType.Edit:
e.Visible = permission[1];
break;
case ColumnCommandButtonType.Delete:
e.Visible = permission[2];
break;
case ColumnCommandButtonType.New:
e.Visible = permission[3];
break;
}
}
else
{
switch (e.ButtonType)
{
case ColumnCommandButtonType.Edit:
e.Visible = false;
break;
case ColumnCommandButtonType.Delete:
e.Visible = false;
break;
case ColumnCommandButtonType.New:
e.Visible = false;
break;
}
}
}
}
I figure that I need to put a
protected void Page_Init(object sender, EventArgs e)
{
DataSource.SelectParameters["StaffId"].DefaultValue = User.Identity.Name;
}
code snippet in there somewhere, but I am really not sure where or how, so any advice would be really appreciated.
Thank you
completed this using the advice from #done_merson on How to use User.Identity.Name as a parameter for SqlDataSource in ASP.NET?
works a charm! Thank you #done_merson

Implement Infinite scroll with ViewModel And Retrofit in recyclerview

Before adding viewmodel & livedata , i successfully implemented infinity scroll with retrofit. But after adding viewmodel & livedata with Retrofit, My can't update recyclerview with new data call or viewmodel observer not update the list.
I simply want to infinite scrolling as my code does before. I add a global variable to reuse next page token. Am i missing anything or any sample to implement infinite recyclerview with viewmodel & retrofit will be awesome.
public static String NEXT_PAGE_URL = null;
I coded like that.
My Activity -> PlaceListActivity
placeRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LogMe.d(tag, "onScrollStateChanged:: " + "called");
// check scrolling started or not
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
LogMe.d(tag, "onScrolled:: " + "called");
super.onScrolled(recyclerView, dx, dy);
currentItem = layoutManager.getChildCount();
totalItems = layoutManager.getItemCount();
scrolledOutItems = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
LogMe.d(tag, "currentItem:: " + currentItem);
LogMe.d(tag, "totalItems:: " + totalItems);
LogMe.d(tag, "scrolledOutItems:: " + scrolledOutItems);
if (isScrolling && (currentItem + scrolledOutItems == totalItems)) {
LogMe.d(tag, "view:: " + "finished");
isScrolling = false;
if (ApplicationData.NEXT_PAGE_URL != null) {
LogMe.d(tag, "place adding:: " + " onScrolled called");
ll_loading_more.setVisibility(View.VISIBLE);
// todo: call web api here
callDataFromLocationAPi(type, ApplicationData.NEXT_PAGE_URL, currentLatLng);
} else {
LogMe.d(tag, "next_page_url:: " + " is null");
}
}
}
});
private void callDataFromLocationAPi(String type, String next_page_url, LatLng latLng) {
if (Connectivity.isConnected(activity)) {
showProgressDialog();
model.getNearestPlaces(type, next_page_url, latLng).
observe(activity, new Observer<List<PlaceDetails>>() {
#Override
public void onChanged(#Nullable List<PlaceDetails> placeDetails) {
ll_loading_more.setVisibility(View.GONE);
LogMe.i(tag, "callDataFromLocationAPi: onChanged called !");
hideProgressDialog();
if (placeDetails != null) {
placeDetailsList = placeDetails;
placeListAdapter.setPlaceList(placeDetails);
}
}
});
} else {
showAlertForInternet(activity);
}
}
In PlaceViewModel
public class PlaceViewModel extends AndroidViewModel {
//this is the data that we will fetch asynchronously
private MutableLiveData<List<PlaceDetails>> placeList;
private PlaceRepository placeRepository;
private String tag = getClass().getName();
public PlaceViewModel(Application application) {
super(application);
placeRepository = new PlaceRepository(application);
}
//we will call this method to get the data
public MutableLiveData<List<PlaceDetails>> getNearestPlaces(String type,
String next_page_token,
LatLng latLng) {
//if the list is null
if (placeList == null) {
placeList = new MutableLiveData<>();
//we will load it asynchronously from server in this method
//loadPlaces(type, next_page_token, latLng);
placeList = placeRepository.getNearestPlacesFromAPI(type, next_page_token, latLng);
}
//finally we will return the list
return placeList;
}
}
In my PlaceRepository.java looks
public class PlaceRepository {
private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
#Override
public void migrate(SupportSQLiteDatabase database) {
// Since we didn't alter the table, there's nothing else to do here.
}
};
private PlaceDatabase placeDatabase;
private CurrentLocation currentLocation = null;
private String tag = getClass().getName();
//this is the data that we will fetch asynchronously
private MutableLiveData<List<PlaceDetails>> placeList;
public PlaceRepository(Context context) {
placeDatabase = PlaceDatabase.getDatabase(context);
//addMigrations(MIGRATION_1_2)
placeList =
new MutableLiveData<>();
}
public MutableLiveData<List<PlaceDetails>> getNearestPlacesFromAPI(String type, final String next_page_token, LatLng latLng) {
List<PlaceDetails> placeDetailsList = new ArrayList<>();
try {
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<Example> call = apiService.getNearbyPlaces(type,
latLng.latitude + "," +
latLng.longitude, ApplicationData.PROXIMITY_RADIUS,
ApplicationData.PLACE_API_KEY, next_page_token);
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
try {
Example example = response.body();
ApplicationData.NEXT_PAGE_URL = example.getNextPageToken();
// next_page_url = example.getNextPageToken();
LogMe.i(tag, "next_page_url:" + ApplicationData.NEXT_PAGE_URL);
if (example.getStatus().equals("OK")) {
LogMe.i("getNearbyPlaces::", " --- " + response.toString() +
response.message() + response.body().toString());
// This loop will go through all the results and add marker on each location.
for (int i = 0; i < example.getResults().size(); i++) {
Double lat = example.getResults().get(i).getGeometry().getLocation().getLat();
Double lng = example.getResults().get(i).getGeometry().getLocation().getLng();
String placeName = example.getResults().get(i).getName();
String vicinity = example.getResults().get(i).getVicinity();
String icon = example.getResults().get(i).getIcon();
String place_id = example.getResults().get(i).getPlaceId();
PlaceDetails placeDetails = new PlaceDetails();
if (example.getResults().get(i).getRating() != null) {
Double rating = example.getResults().get(i).getRating();
placeDetails.setRating(rating);
}
//List<Photo> photoReference = example.getResults().
// get(i).getPhotos();
placeDetails.setName(placeName);
placeDetails.setAddress(vicinity);
placeDetails.setLatitude(lat);
placeDetails.setLongitude(lng);
placeDetails.setIcon(icon);
placeDetails.setPlace_id(place_id);
//placeDetails.setPlace_type(place_type_title);
double value = ApplicationData.
DISTANCE_OF_TWO_LOCATION_IN_KM(latLng.latitude, latLng.longitude, lat, lng);
//new DecimalFormat("##.##").format(value);
placeDetails.setDistance(new DecimalFormat("##.##").format(value));
String ph = "";
if (example.getResults().
get(i).getPhotos() != null) {
try {
List<Photo> photos = example.getResults().
get(i).getPhotos();
//JSONArray array = new JSONArray(example.getResults().
//get(i).getPhotos());
//JSONObject jsonObj = new JSONObject(array.toString());
//ph = jsonObj.getString("photo_reference");
ph = photos.get(0).getPhotoReference();
//LogMe.i(tag, "\n" + ph);
} catch (Exception e) {
e.printStackTrace();
//placeDetails.setPicture_reference(ph);
//PLACE_DETAILS_LIST.add(placeDetails);
//LogMe.i(tag, "#### Exception Occureed ####");
ph = "";
//continue;
}
}
placeDetails.setPicture_reference(ph);
placeDetailsList.add(placeDetails);
placeList.postValue(placeDetailsList);
}
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
} catch (RuntimeException e) {
//hideProgressDialog();
Log.d("onResponse", "RuntimeException is an error");
e.printStackTrace();
} catch (Exception e) {
Log.d("onResponse", "Exception is an error");
}
return placeList;
}
}
I precise code due to question simplicity.
Though you already use android-jetpack, take a look at Paging library. It's specially designed for building infinite lists using RecyclerView.
Based on your source code, I'd say that you need PageKeyedDataSource, here is some example which includes info about how to implement PageKeyedDataSource -
7 steps to implement Paging library in Android
If talking about cons of this approach:
You don't need anymore to observe list scrolling (library doing it for you), you just need to specify your page size in the next way:
PagedList.Config myPagingConfig = new PagedList.Config.Builder()
.setPageSize(50)
.build();
From documentation:
Page size: The number of items in each page.
Your code will be more clear, you'll get rid of your RecyclerView.OnScrollListener
ViewModel code will be shorter, it's will provide only PagedList:
#NonNull
LiveData<PagedList<ReviewSection>> getReviewsLiveData() {
return reviewsLiveData;
}

How to hide rows while editing a specific row from the user in gridview

I have a web application which is connected to SQL server management studio.
I have one problem to finish my application.
In my gridview users are able to edit their own reservation, but once i reach update part for the gridview it shows me that the users are able to edit the other reservation and here are some images to show you the meaning of this:
1) this the code in my gridview events
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
foreach (GridViewRow row in GridView1.Rows)
{
if ((row.Cells[9].Text.Trim()).Equals(HttpContext.Current.User.Identity.Name) == false)
{
//row.BackColor = Color.Red;
row.Cells[0].Controls.Clear();
}
}
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
Label1.Text = "Changed";
GridViewRow selectedRow = GridView1.Rows[e.NewEditIndex];
foreach (GridViewRow row in GridView1.Rows)
{
int currentIndex = row.RowIndex;
if (currentIndex != e.NewEditIndex)
{
row.Visible = false;
}
}
}
}
2) this is to show you that user can edit only their own reservation
so how can i solve this ?
I have updated GridView's RowEditing event:
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
// Bind Grid Again Here
}

How to add a list of UIelement in Windows Phone

I want to create a page with dynamic control in windows phone.
While doing this I also want to show a progress bar
Below is my code
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
progressstackPanel.Visibility = Visibility.Visible;//progress bar
formScreen = this;
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (!isfst)
{
DrawScreen();
}
else
{
//xTitlePanel is only stack panel in my xaml with vertical orientation
xTitlePanel.UpdateLayout();
}
isfst = true;
progressstackPanel.Visibility = Visibility.Collapsed;
});
}
//Code of DrawScreen which is adding control to my stack panels
private void DrawScreen()
{
if (frm_getset.ChildList != null)
{
String[] arr = frm_getset.ChildList.Split(',');
xTitlePanel.Children.Clear();
PrepareControls prepcontrol = new PrepareControls();
foreach (AttributeGetSet a in _Attribute)
{
//this will return a stackpanel containing
// button/textbox etc.depending on a
StackPanel sp = prepcontrol.getControl(i, a.Label, a, formScreen);
try
{
xTitlePanel.Children.Add(sp);
///Here I get a eception only one control is added first one
/// for anyone it is getting a exception Argument
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
i += 1;
}
The system is adding only one control and when ever it try to execute xTitlePanel.Children.Add(sp); it will get an exception.
I solved the problem ,"xTitlePanel" is a StackPanel I created in my XAML. I found you can not add more that one element from Dispatcher to a control crated on xaml. Like that. so I have to create local stack and add controls to the that local stack panel then and after complete I add the local stack panel to xTitlePanel. NOW my code looks like below
filteredList = new List<FormGetSet>();
if (frm_getset.ChildList != null)
{
String[] arr = frm_getset.ChildList.Split(',');
foreach (String x in arr)
{
filteredList.Add(_template.list_fromgetset.Where(p => p.FormID.Contains(x.Trim())).ToList()[0]);
}
}
xTbox_FormNameHeader.Text = frm_getset.NAME;
_Attribute = new List<AttributeGetSet>();
_Attribute = frm_getset.list_attributegetset;
xTitlePanel.Children.Clear();
StackPanel spPanel = new StackPanel();
spPanel.Orientation = System.Windows.Controls.Orientation.Vertical;
spPanel.Background = new SolidColorBrush(Colors.Transparent);
//xTitlePanel.Children.Add(PrepareControls.getControl(1, "LABEL", "16"));
int i = 1;
// List<AttributeGetSet> _Attribute2 = new List<AttributeGetSet>();
foreach (AttributeGetSet a in _Attribute)
{
PrepareControls prepcontrol = new PrepareControls();
StackPanel sp= prepcontrol.getControl(i, a.Label, a, this);
try
{
spPanel.Children.Add(sp);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
//xTitlePanel.Background = new SolidColorBrush(Colors.White);
//_Attribute2.Add(a);
i += 1;
}
xTitlePanel.Children.Add(spPanel);

return result from async operation in mvvm

I have a viewModel named CarsList with main property
public ObservableCollection<Car> Cars
{
get
{
if (_cars.Count == 0)
{
IsBusy = true;
_ws.GetCarsCompleted += new EventHandler<GetCarsCompletedEventArgs>(GetCarsCompleted);
_ws.GetCarsAsync(_app.HandlerId);
}
return _cars;
}
set
{
if (_cars != value)
{
if (_cars != null)
{
Unsubscribe(_cars);
}
_cars = value;
if (_cars != null)
{
Subscribe(_cars);
}
RaisePropertyChanged("Cars");
}
}
}
private void GetCarsCompleted(object sender, GetCarsCompletedEventArgs e)
{
//_cars = e.Result;
IsBusy = false;
}
When view gets _cars and the list is empty I must wait to get collection of cars from wcf service, and there is a problem because it is async operation.
Or maybe if list is empty I should return null, and fire async operation, and in asynccompleted set _cars to result from the wcf service?
I can only guess that you are trying to set up a view binding and property change notification. If I am right I would change you code as follows:
public void GetCars(Int32 handlerId)
{
_ws.GetCarsCompleted += new EventHandler<GetCarsCompletedEventArgs>GetCarsCompleted);
IsBusy = true;
_ws.GetCarsAsync(handlerId);
}
public ObservableCollection<Car> Cars
{
get
{
return _cars;
}
set
{
if (_cars != value)
{
_cars = value;
RaisePropertyChanged("Cars");
}
}
private void GetCarsCompleted(object sender, GetCarsCompletedEventArgs e)
{
_ws.GetCarsCompleted -= new EventHandler<GetCarsCompletedEventArgs>GetCarsCompleted);
IsBusy = false;
if (e.Error != null)
{
//Error handler
}
else
{
Cars = e.Result;
}
}
And then the view binding (in the case of a DataGrid) would look something like this..
<DataGrid IsReadOnly="True"
ItemsSource="{Binding Cars}"
.........
........./>