c# .net grid app search page - c#

Trying to use the guide from https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868180.aspx
My app contains Personal trainers, and personal trainers have their customers.
I want to be able to search for customers.
This is how far I am: I can search for customers on first/lastname and it will say how many results there are, IE results(3), but it will not show them.
I've included my data:
using PersonalTrainerGridApp.Data;
The if statement in navigationHelper_LoadState is confusing me, I'm not sure what to have in it, and I'm not sure if the Filter_Checked is correct.
Anyone have some pointers? thanks for formatting!
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
var queryText = e.NavigationParameter as String;
// Initialize the results list.
AllResultsCollection = new Dictionary<string, IEnumerable<SampleDataSource>>();
// Keep track of the number of matching items.
var totalMatchingItems = 0;
var filterList = new List<Filter>();
var groups = await SampleDataSource.GetPersonalTrainerAsync();
foreach (var group in groups)
{
var matchingItems = group.Customers.Where(
item =>
item.FirstName.IndexOf(
queryText, StringComparison.CurrentCultureIgnoreCase) > -1 || item.LastName.IndexOf(
queryText, StringComparison.CurrentCultureIgnoreCase) > -1 );
int numberOfMatchingItems = matchingItems.Count();
totalMatchingItems += numberOfMatchingItems;
if (numberOfMatchingItems > 0)
{
AllResultsCollection.Add(group.Customers, matchingItems);
filterList.Add(new Filter(group.Customers, numberOfMatchingItems));
}
}
// Create an entry for "All" for viewing all search results.
filterList.Insert(0, new Filter("All", totalMatchingItems, true));
// Communicate results through the view model
this.DefaultViewModel["QueryText"] = '\"' + queryText + '\"';
this.DefaultViewModel["Filters"] = filterList;
this.DefaultViewModel["ShowFilters"] = true;
}
/// <summary>
/// Invoked when a filter is selected using a RadioButton when not snapped.
/// </summary>
/// <param name="sender">The selected RadioButton instance.</param>
/// <param name="e">Event data describing how the RadioButton was selected.</param>
void Filter_Checked(object sender, RoutedEventArgs e)
{
// Retrieve the data context of the sender (the selected radio button).
// This gives us the selected Filter object.
var filter = (sender as FrameworkElement).DataContext as Filter;
// Mirror the change into the CollectionViewSource.
// This is most likely not needed.
if (filtersViewSource.View != null)
{
filtersViewSource.View.MoveCurrentTo(filter);
}
// Determine which filter was selected
if (filter != null)
{
// Mirror the results into the corresponding Filter object to allow the
// RadioButton representation used when not snapped to reflect the change
filter.Active = true;
// TODO: Respond to the change in active filter by setting this.DefaultViewModel["Results"]
// to a collection of items with bindable Image, Title, Subtitle, and Description properties
if (filter.Name.Equals("All"))
{
var tempResults = new List<SampleDataSource>();
// Add the items from each group to the temporary results
// list.
foreach (var group in AllResultsCollection)
{
tempResults.AddRange(group.Value);
}
// Display the items.
this.DefaultViewModel["Results"] = tempResults;
}
else if (AllResultsCollection.ContainsKey(filter.Name))
{
this.DefaultViewModel["Results"] =
new List<SampleDataSource>(AllResultsCollection[filter.Name]);
}
// Ensure results are found
object results;
ICollection resultsCollection;
if (this.DefaultViewModel.TryGetValue("Results", out results) &&
(resultsCollection = results as ICollection) != null &&
resultsCollection.Count != 0)
{
VisualStateManager.GoToState(this, "ResultsFound", true);
return;
}
}
// Display informational text when there are no search results.
VisualStateManager.GoToState(this, "NoResultsFound", true);
}
Thanks in advance, much appreciated :-)

Related

Xamarin forms - MVVM observable collection always 0 when getting values

I have 2 observable collections, the idea is to load the Master Collection with all data from my database related to the form. I would filter this collection and use the filtered results to set Actor Collection. The reason im trying this is to reduce the time it takes to convert b64 image to ImageSource for larger collections. I like to convert these image only once
Onload of the form the Master Collection is populated with the items needed but when i click on a filter option, Master Collection is always 0. I can see onload 119 entries added to the collection
public ActorCollectionVM(INavigation navigation)
{
Navigation = navigation;
// one time only populate
Device.BeginInvokeOnMainThread(() =>
{
UserDialogs.Instance.ShowLoading("Loading");
Database db = new Database();
List<TMDB_Person> persons = db.GetAllPersons();
ImageUtility util = new ImageUtility();
foreach (TMDB_Person person in persons)
{
person.Profile_Thumb_Image = util.Base64ToImage(person.B64_Profile_Thumb_Image);
MasterCollection.Add(person);
}
ActorCollection = MasterCollection;
UserDialogs.Instance.HideLoading();
});
}
private void LetterSearch_Click(object sender, EventArgs args)
{
ActorCollectionVM context = (ActorCollectionVM)BindingContext;
context.ActorCollection.Clear();
Button btn = (Button)sender;
btn.TextColor = (Color)Application.Current.Resources["ThemeColor"];
if (btn.Text != "ALL")
{
foreach (TMDB_Person person in context.MasterCollection.Where(x => x.Name[0].ToString().ToLower() == btn.Text.ToLower()))
context.ActorCollection.Add(person);
}
else
{
context.ActorCollection = context.MasterCollection;
}
}

Finding the value of a list view item and comparing it to a value in Azure Database

I am developing a Windows store app for Windows 8.1 in Visual Studio 2013 using C# and XAML.
I have a table that stores goals and rewards, these are displayed in a list view in my app. I want the user to be able to select one of these goals and have it marked as complete.
There is a column in my database which is set to false at the beginning and when the list view item is selected I want to find that item in the database and change the column to true.
Does anyone have any idea how to do this?
Here is my code:
private async void Goals_List_Tapped(object sender, TappedRoutedEventArgs e)
{
// Create a list of all names stored in goalsDetails table in DB
var goalsComplete = new List<goalsDetails>(await goalsTable
.Where(goalsDetails => goalsDetails.UsernameID == goalsDetails.UsernameID && goalsDetails.Goal == goalsDetails.Goal && goalsDetails.Reward == goalsDetails.Reward && goalsDetails.GoalComplete == false)
.ToListAsync());
for (int i = 0; i < goalsComplete.Count; i++)
{
//Goals_List is the name of my listview in XAML
if (Goals_List.SelectedIndex == i)
{
var user = goalsComplete.FirstOrDefault();
// setting new details to push to database
var newGoalDetails = new goalsDetails
{
UsernameID = user.UsernameID,
Id = user.Id,
Goal = Goal_Text.Text,
GoalComplete = true,
DeadlineDate = Deadline_Date_Picker.Date.ToString("dd:MMMM:yyyy"),
ReminderTime = Reminder_Time_Picker.Time.ToString(),
Reward = Reward_Text.Text,
};
await goalsTable.UpdateAsync(newGoalDetails);
}
}
}
My problem is that when the item is selected in the listview, the value is never being changed to true.
Thanks! Any help would be MUCH appreciated!

Why ItemContainerGenerator.ContainerFromIndex() returns null and how to avoid this behavior?

I'm using this snippet to analyze the rows I've selected on a datagrid.
for (int i = 0; i < dgDetalle.Items.Count; i++)
{
DataGridRow row = (DataGridRow)dgDetalle.ItemContainerGenerator.ContainerFromIndex(i);
FrameworkElement cellContent = dgDetalle.Columns[0].GetCellContent(row);
// ... code ...
}
The cycle runs smoothly, but when processing certain indexes, the second line throws a null exception. MSDN's documentation says that ItemContainerGenerator.ContainerFromIndex(i) will return null if 'if the item is not realized', but this doesn't help me to guess how could I get the desired value.
How can I scan all the rows? Is there any other way?
UPDATE
I'm using this snippet to read a CheckBox as explained here. So I can't use binding or ItemSource at all unless I change a lot of things. And I cannot. I'm doing code maintenance.
Try this,
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
grid.UpdateLayout();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
The DataGrid is virtualizing the items, the respective rows (i.e. containers) are only created when the row is in view.
You could either turn off virtualization (which makes the first time loading very slow if you have many items, also the memory usage will be higher) or you just iterate over the data and check the values of the data objects' properties which should be bound to the data-grid. Usually you should not need the UI elements at all...
Use this subscription:
TheListBox.ItemContainerGenerator.StatusChanged += (sender, e) =>
{
TheListBox.Dispatcher.Invoke(() =>
{
var TheOne = TheListBox.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
if (TheOne != null)
// Use The One
});
};
In addition to other answers: items aren't available in constructor of the control class (page / window / etc).
If you want to access them after created, use Loaded event:
public partial class MyUserControl : UserControl
{
public MyUserControl(int[] values)
{
InitializeComponent();
this.MyItemsControl.ItemsSource = values;
Loaded += (s, e) =>
{
for (int i = 0; i < this.MyItemsControl.Items.Count; ++i)
{
// this.MyItemsControl.ItemContainerGenerator.ContainerFromIndex(i)
}
};
}
}
In my case grid.UpdateLayout(); didn't help an I needed a DoEvents() instead:
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
WPFTools.DoEvents();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
/// <summary>
/// WPF DoEvents
/// Source: https://stackoverflow.com/a/11899439/1574221
/// </summary>
public static void DoEvents()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(
delegate (object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}), frame);
Dispatcher.PushFrame(frame);
}

Can someone tell me what's wrong with this code?

I'm trying to implement a search as you type (like in iTunes). I am using an ObjectListView. Further, I have a textbox that is used to do the search as shown below:
private void textBoxSearch_TextChanged(object sender, EventArgs e)
{
string txt = textBoxSearch.Text;
TextMatchFilter filter = null;
if (!String.IsNullOrEmpty(txt))
{
filter = TextMatchFilter.Contains(myObjectListView, txt);
}
// Setup a default renderer to draw the filter matches
if (filter == null)
myObjectListView.DefaultRenderer = null;
else
{
myObjectListView.DefaultRenderer = new HighlightTextRenderer(filter);
// Uncomment this line to see how the GDI+ rendering looks
myObjectListView.DefaultRenderer = new HighlightTextRenderer { Filter = filter, UseGdiTextRendering = false };
}
// Some lists have renderers already installed
HighlightTextRenderer highlightingRenderer = myObjectListView.GetColumn(0).Renderer as HighlightTextRenderer;
if (highlightingRenderer != null)
highlightingRenderer.Filter = filter;
myObjectListView.ModelFilter = filter;
}
Can someone figure out why this doesn't work?
The above code is meant to filter search results as the user types in the textbox (Like iTunes does, if you have ever used itunes). Apparently, up to this point, nothing happens. It seems like this code does not even execute.
Per this, the ObjectListView has a property named UseFiltering that is false by default and must be set to true to enable filtering.

Properties value resetting within another event

I am having some trouble with getting the formatting to occur correctly. I believe it stems from what is probably incorrect understanding of the events that I am attempting to make the changes in.
any direction would be great
private void so_FetchData(object sender, FetchEventArgs eArgs)
{
if (m_so != null && m_so.Rows.Count > (m_soRowCount + 1))
{
DataRow soDr = m_so.Rows[m_soRowCount++];
if (soDr != null)
{
var compResID = (int) soDr["CompResID"];
var result = (ComplianceLevel) soDr["Result"];
var sectNum = (int) soDr["JobSectType"];
var sectName = soDr["S" + sectNum + "Name"] as string;
var sectTxt = soDr["S" + sectNum + "Text"] as string;
Fields["CompLev"].Value = (result == ComplianceLevel.OtherThanSerious) ? "Other Than Serious" : result.ToString();
m_sectInfo = new SectInfo(sectName, sectTxt);
m_causes = new Causes(compResID);
m_actions = new Actions(compResID);
subReport1.Report = m_sectInfo;
subReport2.Report = m_causes;
subReport3.Report = m_actions;
eArgs.EOF = false;
}
}
else
{
eArgs.EOF = true;
}
}
private void eh_BeforePrint(object sender, EventArgs e)
{
//decide where the bottom border should be draw to
if (m_actions != null && m_actions.ShouldShowBottBorder)
{
subReport3.Border.BottomStyle = BorderLineStyle.ThickSolid;
subReport2.Border.BottomStyle = BorderLineStyle.Solid;
}
else if (m_causes != null && m_causes.ShouldShowBottBorder)
{
subReport2.Border.BottomStyle = BorderLineStyle.ThickSolid;
}
else
{
subReport1.Border.BottomStyle = BorderLineStyle.ThickSolid;
}
}
the issue is that every time I step through the eh_BeforePrint method, the values always equate to false even though I step through the sub reports and the values are properly set. What is happening to cause the bool property to reset to false?
Just changing it if there are any records to print in the Fetch_Data method of each sub report.
private void Causes_FetchData(object sender, FetchEventArgs eArgs)
{
if (m_pos < m_corrs.Count)
{
if (!ShouldShowBottBorder)
ShouldShowBottBorder = true;
//...
}
}
You cannot be assured that the BeforePrint event raises exactly after the corresponding FetchData event. For example, FetchData may fire many times for several records, but due to some keep together logic in the layout engine, it may take several records before ActiveReports knows which page it will commit a section to. Therefore, it is pretty common for FetchData to be raised for several events before the corresponding BeforePrint events are raised.
If I understand your code properly there is a bigger problem though. It appears you are calculating values in your subreports (m_causes and m_actions appear to be actual subreports). If that is the case you cannot reliably calculate values in your subreports and pass them out to the parent report. Instead, you'll need to calculate those values in your parent report. However, usually you can add some shared function to calculate the value and call it from the parent report, and then pass that value into the subreports.
Comment here with some more information if you have specific questions about doing that.
On an unrelated note, you can get a pretty significant performance boost if you change the way you're initializing your subreports. Always initialize your subreports in the ReportStart event and then set their data in the format event of the section containing the Subreport control. This way you initialize each subreport once instead of initializing each subureport for every record. For example:
private void so_ReportStart()
{
subreport1.Report = new SectInfo();
subreport2.Report = new Causes();
subreport3.Report = new Actions();
}
private void Detail_Format()
{ // assuming Detail is the section containing your subreports:
((SectInfo)subreport1.Report).SetParameters(Fields["sectName"].Value, Fields["sectTxt"].Value);
((Causes)subreport2.Report).SetParameters(Fields["compResID"].Value);
((Actions)subreport3.Report).SetParameters(Fields["compResID"].Value);
}
You would setup those "Fields" values in FetchData similar to how your initializing the subreports now. Something like the following:
private void so_FetchData(object sender, FetchEventArgs eArgs)
{
if (m_so != null && m_so.Rows.Count > (m_soRowCount + 1))
{
DataRow soDr = m_so.Rows[m_soRowCount++];
if (soDr != null)
{
var compResID = (int) soDr["CompResID"];
var result = (ComplianceLevel) soDr["Result"];
var sectNum = (int) soDr["JobSectType"];
var sectName = soDr["S" + sectNum + "Name"] as string;
var sectTxt = soDr["S" + sectNum + "Text"] as string;
Fields["CompLev"].Value = (result == ComplianceLevel.OtherThanSerious) ? "Other Than Serious" : result.ToString();
/** BEGIN NEW CODE **/
Fields["sectName"].Value = sectName;
Fields["sectTxt"].Value = sectTxt;
Fields["compResID"].Value = compResId;
/** END NEW CODE **/
/** OLD CODE:
m_sectInfo = new SectInfo(sectName, sectTxt);
m_causes = new Causes(compResID);
m_actions = new Actions(compResID);
subReport1.Report = m_sectInfo;
subReport2.Report = m_causes;
subReport3.Report = m_actions;
**/
eArgs.EOF = false;
}
}
else
{
eArgs.EOF = true;
}
}
To learn more about the events in ActiveReports see the Report Events concepts topic in the ActiveReports Online Help.
To learn more about passing data into Subreports see Subreports with Run-Time Data Sources in the ActiveReports Online Help.
Scott Willeke
GrapeCity inc.

Categories

Resources