Testing WPF ViewModel with Xunit - c#

Recently I was put on new a team at work and the lead told me to write unit tests for the code they had written. I'm really not sure where to start. The application is a WPF written in C#. I'm a newbie to both WPF and C#. They mentioned using Xunit.
Here is first two functions of the class. There is mix of protected and public functions i have to unit test,
The class type is public class DataTableModel<T> : ViewModelBase
public DataTableModel()
{
//Setup Drag and Drop Commands:
RecordReceivedCommand = new DataTableReceivedCommand<T>(this);
RecordRemovedCommand = new DataTableRemovedCommand<T>(this);
RecordInsertedCommand = new DataTableInsertedCommand<T>(this);
View = CollectionViewSource.GetDefaultView(Records);
}
/// <summary>
/// This method sets up the properties for the table. By default, the first DisplayOption is selected, no search criteria is applies, and only 10 records should be returned.
/// </summary>
/// <param name="displayOption">The selected display option</param>
protected void InstantiateTable(int displayOption = 0)
{
_displayOption = displayOption;
_searchCriteria = "";
_displayAmount = "10";
_currentPage = 1;
_userMessage = "Retrieving data...";
TriggerUpdate();
}
These functions are called from above so I thought I'd include them.
/// <summary>
/// This method is responsible for handling the updates to the recordset that the DataGrid will display.
/// Upon changes to the search criteria, display amount, display option and the current page, this method will be triggered
/// </summary>
/// <param name="resetPage">Inidicates whether the grid should return to page 1.</param>
protected void TriggerUpdate(bool resetPage = false)
{
_currentPage = resetPage ? 1 : _currentPage; //only reset to the first page if indicated
UserMessage = "Retrieving data...";
//Retrieve the records if the delegate has been set
GetRecords?.Invoke();
UserMessage = Records.Count == 0 ? "No data found" : "";
Message_ZIndex = !String.IsNullOrWhiteSpace(UserMessage) ? 1 : -1;
//update the page navigations button's settings when the pages are reset
UpdatePagination();
}
/// <summary>
/// Update the ability to navigate through the datatable's pages.
/// Upon changes the the search criteria, display amount, display option, the number of pages and the current page, this method will be
/// triggered
/// </summary>
private void UpdatePagination()
{
if (Pages > 1)
{
if (_currentPage == 1)
{
GoToFirstPage = false;
GoToPrevPage = false;
GoToNextPage = true;
GoToLastPage = true;
}
else if (_currentPage == Pages)
{
GoToFirstPage = true;
GoToPrevPage = true;
GoToNextPage = false;
GoToLastPage = false;
}
else
{
GoToFirstPage = true;
GoToPrevPage = true;
GoToNextPage = true;
GoToLastPage = true;
}
}
else
{
GoToFirstPage = false;
GoToPrevPage = false;
GoToNextPage = false;
GoToLastPage = false;
}
}
/// <summary>
/// Get's the information for the datatable's columns
/// (NOTE: This method is currently only called via ".Invoke" within the DataTable control.)
/// </summary>
/// <returns>A List of the DataTableDisplay attributes for the columns in the table</returns>
public List<DataTableDisplay> GetTableColumnInformation()
{
List<DataTableDisplay> attributes = new List<DataTableDisplay>();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach(PropertyInfo property in properties)
{
DataTableDisplay attr = property.GetCustomAttribute<DataTableDisplay>(false);
if (attr != null && !String.IsNullOrWhiteSpace(attr.ColumnTitle))
{
attributes.Add(attr);
}
}
return attributes;
}
At first I wanted to test the constructor, but then I didn't know how to check for the command vars so i moved on to the InstantiateTable function. This is what i got. Still having to create object so using the Constructor but when i tried calling x.InstantiateTable() I noticed it was protected so I cant do that.
Test case for creating an DataTableModel Object. It had dynamic type so i just made it int.
[Fact]
public void DataTableModel_Created()
{
DataTableModel<int> x = new DataTableModel<int>();
Assert.Equal(0, x.DisplayOption);
Assert.Equal("", x.SearchCriteria);
Assert.Equal("10", x.DisplayAmount);
Assert.Equal(1, x.CurrentPage);
Assert.Equal("Retrieving data...", x.UserMessage);
}
Another protected function i have to unit test.
protected List<T> UpdateTable(List<T> data)
{
_totalCount = data.Count;
int recordLimit = String.IsNullOrEmpty(DisplayAmount) ? 0 : Convert.ToInt32(DisplayAmount);
int startingRecord = recordLimit == 0 ? 0 : (_currentPage == 1 ? 1 : 1 + (recordLimit * (_currentPage - 1)));
int recordsToSkip = (CurrentPage - 1) * recordLimit;
int endingRecord = recordLimit == 0 ? 0 : recordLimit > _totalCount ? _totalCount : startingRecord + recordLimit - 1;
Pages = recordLimit == 0 ? 0 : _totalCount <= recordLimit ? 1 : _totalCount % recordLimit > 0 ? (_totalCount / recordLimit) + 1 : _totalCount / recordLimit;
List<T> displayRecords = data.Skip(recordsToSkip).Take(recordLimit).ToList();
DisplayMessage = endingRecord <= _totalCount ? $"Showing {(displayRecords.Count == 0 ? 0 : startingRecord)} to {endingRecord} of {_totalCount} entries" : $"Showing {startingRecord} to {_totalCount} of {_totalCount} entries";
return displayRecords;
}
And a delegate function? I'm supposed to test
public delegate List<T> Filter(List<T> data);
I am not sure how to approach. The few unit tests i did in university were basic objects and didn't call other objects and what not. I have read about mocking and stubbing objects, I think it may be good to mock database to populate the tables.

Do not unit-test functions. Unit-test view-models.
A view-model exposes properties and commands which are bound by XAML to GUI controls so that the user can interact with them.
All these properties and commands are already public, otherwise they would not be visible from XAML, so your tests can access them too.
Most C# programmers will not think twice before converting private and protected to public, or converting to internal and then using InternalsVisibleTo, but in my opinion that's all misguided. We must be testing against the interface, not against the implementation; therefore, we must be engaging in black-box testing, not white-box testing.
When it comes to testing view-models in WPF, this means you should only test things that are exposed to XAML.
So, your tests should set values to view-model properties as if these values were set by GUI controls, invoke view-model commands as if these commands were triggered by GUI buttons.
Then, your tests should examine nothing but how the values of view-model properties change as a result. That's what the user would see on the screen.

Related

c# .net grid app search page

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 :-)

Programmatically adding two buttons to each row as it loads

I've created a ListView in a new WPF window and also a function that populates the ListView when it is called. This function just takes the URL of my web server where I've stored the data, increments the "id" and gets the data and stores it in the ListView. Therefore it populates the ListView with a certain number of items.
The problem I'm facing is that I want to add two buttons, ON & OFF, to each ListView item as it gets populated programmatically. i.e, if 16 items are added, I want 2 buttons for each item, and if it's 12 items, the similar procedure. Here's my code:
namespace user_login
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Window1 W = new Window1();
public MainWindow()
{
InitializeComponent();
}
public void populate()
{
int i;
int num = 16;
for (i = 1; i <= num; i++)
{
string val = Convert.ToString(i);
string currentUrl = "http://xpleria.com/devices.php?query=dev&id=";
string newUrlWithChangedSort = ReplaceQueryStringParam(currentUrl, "id", val);
string result = getcontent(newUrlWithChangedSort);
W.list1.Items.Add(result);
}
}
public string getcontent(string URL)
{
string content = "";
// Get HTML data
WebClient client = new WebClient();
try
{
content = client.DownloadString(URL);
}
catch (Exception)
{
System.Windows.Forms.MessageBox.Show("No Connection detected!!!");
}
return content;
}
public static string ReplaceQueryStringParam(string currentPageUrl, string paramToReplace, string newValue)
{
string urlWithoutQuery = currentPageUrl.IndexOf('?') >= 0
? currentPageUrl.Substring(0, currentPageUrl.IndexOf('?'))
: currentPageUrl;
string queryString = currentPageUrl.IndexOf('?') >= 0
? currentPageUrl.Substring(currentPageUrl.IndexOf('?'))
: null;
var queryParamList = queryString != null
? HttpUtility.ParseQueryString(queryString)
: HttpUtility.ParseQueryString(string.Empty);
if (queryParamList[paramToReplace] != null)
{
queryParamList[paramToReplace] = newValue;
}
else
{
queryParamList.Add(paramToReplace, newValue);
}
return String.Format("{0}?{1}", urlWithoutQuery, queryParamList);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string user = textbox1.Text;
string password = textbox2.Password;
string currentUrl = "http://xpleria.com/login.php?query=login&user=wcam&pass=wireless";
string newUrlWithChangedSort = ReplaceQueryStringParam(currentUrl, "user", user);
string newUrl = newUrlWithChangedSort;
string FinalUrl = ReplaceQueryStringParam(newUrl, "pass", password);
string result= getcontent(FinalUrl);
string value = result.Substring(0, 8);
string invalid = "xpleria0";
string valid = "xpleria1";
if (value.Equals(invalid))
{
System.Windows.MessageBox.Show("The Username and/or Password you have entered is invalid, please try again");
}
else if (value.Equals(valid))
{
string sessionID = result.Substring(8, 32);
System.Windows.MessageBox.Show("HI, WELCOME CLETA");
this.Close();
using (new user_login.loading.PleaseWait(this.Location))
{
W.Show();
populate();
}
}
}
public System.Drawing.Point Location { get; set; }
}
}
I'm going to recommend you take a step back and start giving some serious consideration to organizing your code. I realize this isn't an answer to the question you asked but it is the answer to the question you should be asking.
First of all, all code relating to the retrieval of these items from the URL should be moved into a class of some kind. This class should accept the URL string as a constructor parameter and gather all the appropriate data. You should then create another class which you will use to populate with the data for each individual item and then expose this list. By the time you're done the code in your window should little more complex than:
var ItemsGetter = new ItemsGetter(URL);
foreach(var Item in ItemsGetter.Items)
{
// Populate the ListView
}
Once you're done with that I recommend you create a UserControl. User controls are extremely useful in situations where you need to represent a dynamic number of data entities each with their own set of controls which allow operations to be performed on each one. You should create a UserControl with a label and the two buttons you need. The UserControl's constructor should expect a parameter of the data type you created to represent each one of your classes. From there you can have the buttons operate on the data type as necessary.
Finally, you'll probably need a way to have the UserControl interact with the Window. Say for example one of your buttons is "Delete". You'd probably want the item to disappear from the list once the operation is complete. Don't be tempted to tie in your control with the Window by passing it as a parameter or something. Instead, read up on Action events and learn how you can create an event on the user control which you bind in the foreach loop of the Window when you're populating the list view. When the UserControl has completed the delete operation triggered by the button you can raise the UserControl's event which will prompt the Window to remove the control from the List View.
Last but not least, NAME YOUR CONTROLS.
Hopefully this helps.

Having trouble getting parent class call child class method - reflection used

Problem: Program flow is not going to the child class implementation of ValidateDynData when I call ValidateDynData in my parent class.
I create my instance of my class using reflection. When I invoke a method in the child class from another project, it winds up in the correct method in the child class (and not parent's same-name method), so it seems like that is set up correctly.
This is what the reflection part looks like in my other project/class:
**Note 3/7/2013: I added more info so you can get the general feel for this. It gets the number of boxes, loops thru the number of boxes, and for each box, creates a control and adds a tab to the form. This is the main CTool visual studio project and is a class in the project, which is a form. When I press a button on the form, with the info (selected) on which child class I'm going to be creating later, it goes to this method , CreatTabs():
cb = new CB();
int errValue = cb.FindUsbHid(ref HWndBoxID); //see how many boxes there are
if (errValue == 0 && HWndBoxID[0, 1] != 0)
{
for (int i = 0; i < cb.cbInfos.Length; i++)
{
if (controls[i] == null)
{
CB cb1 = new CB(); //need one for each box found or concurrent programming will fail
errValue = cb1.FindUsbHid(ref HWndBoxID); //need to do for each box to get all info
/////////////////////////////////////////
if (errValue == 0)
{
_assembly = Assembly.LoadFrom(programDll);
_type = _assembly.GetType("CrWriter.PC");
_objectInstance = Activator.CreateInstance(_type);
_parameters = new Object[] { cb1, programDll, templateArr, itsDll, cert, i, cb1.cbInfos[i].boxID };
controls[i] = new Control();
//The following lands in my child's GetPC method
//My parent also has a method called GetPC and that is called from the child.
//Then, most of the program flow is in the parent until I need to call ValidateDynData,
//discussed below
controls[i] = (Control)_type.InvokeMember("GetPC", BindingFlags.Default | BindingFlags.InvokeMethod, null, _objectInstance, _parameters);
controls[i].Dock = DockStyle.None;
this.Controls.Add(controls[i]);
TabPage newPage = new TabPage(string.Format("{0}:{1}", cb1.cbInfos[i].usbHandle, cb1.cbInfos[i].boxID));
Console.WriteLine("frmUserForm::CreateTabs - Making new tab with cb.cbInfos[i].usbHandle:" + cb1.cbInfos[i].usbHandle + " and cb.cbInfos[i].boxID:" + cb1.cbInfos[i].boxID);
InitializeControls(controls[i]);
tabCtrlMain.Size = controls[i].Size;
tabCtrlMain.Width += 20;
tabCtrlMain.Height += 100;
this.Width = tabCtrlMain.Width + 20;
this.Height = tabCtrlMain.Height + 50;
newPage.Controls.Add(controls[i]);
tabCtrlMain.TabPages.Add(newPage);
} //no err for this cb
} //controls not null
} //for all cbInfo's
}//if no err in general finding out how many cb's
this.ResumeLayout();
}
Since my Invocation of GetPC lands in the child class and not the parent, it must be created correctly. So I'm not sure why it's not landing in the correct ValidateDynData method. Maybe I need to cast my object to the programDll somehow. When I run the program and inspect the _objectInstance it could be a problem:
variable..................................................value
base: {GenericCrWriter.GenericPC} ......CrWriter.PC
baseInst: ................................................GenericCrWriter.GenericPC
But then, the _assembly is referring to Ko/PC and not Generic/GenericPC.
Also, my _assembly.GetType looks good. My Generic/parent doesn't have anything named CrWriter.PC
I'm trying to use the child class method instead of the parent class for some child class cases. For some reason, I get to the parent class method, but it never gets to the override in the child. Any ideas why? I've been referring to Calling child class method from parent
but it's not getting to the child's method.
In my PC.cs of the child class (Ko):
**Note 3/8/2013: PC.cs is in the Ko visual studio project. **this contains a form that is displayed
**Note 3/7/2013: This is a separate visual studio project named after the child, let's call it Ko. The important class here is PC.cs. It doesn't do much except pass data to the parent, provide it's custom textBoxes and their names, validate data entered later in the parent's form. Most of the flow is in the parent, otherwise. I'm adding GetPC, setProgramName, setDTF methods.
public partial class PC : GenericPC
{
String childDllName = ""; //I just added this recently but it doesn't seem useful
GenericPC baseInst = new GenericPC();
public Control GetPC(USB_Comm.CB cbInst, string dllSel, TemplateHApp.Templates.TEMPL[] templ, string dll, SC.SC.SITE c0, int slaveIndex, int BoxID)
{
childDllName = dll;
//call parent class methods
setProgramName();
setDTF();
ProcessDynData();
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public void setProgramName()
{
Console.WriteLine("Ko did stuff");
//Update label on form
var f = new F(); //F is a class in child class containing more info on it
string temp = f.GetProgramName();
baseInst.setProgramName(temp); //this is displayed on parent's form
}
public void setDTF()
{
var f = new F();
string temp = f.DTF();
baseInst.setDTF(temp); //this is displayed on parent's form
}
private void ProcessDynamicData()
{
Console.WriteLine("Ko PC::ProcessDynamicData");
Label lbl_dynData0 = new Label();
Label lbl_dynData1 = new Label();
lbl_dynData0.Text = "AT .";
lbl_dynData1.Text = "VL .";
lbl_dynData0.Location = new Point(57, 25);
lbl_dynData1.Location = new Point(57, 45);
Label[] lbl_dynData_Arr = new Label[4];
lbl_dynData_Arr[0] = lbl_dynData0;
lbl_dynData_Arr[1] = lbl_dynData1;
TextBox tb_dynData0 = new TextBox();
TextBox tb_dynData1 = new TextBox();
tb_dynData0.Location = new Point(67, 25);
tb_dynData1.Location = new Point(67, 45);
tb_dynData0.Size = new Size(151,22);
tb_dynData1.Size = new Size(151, 22);
TextBox[] tb_dynData_Array = new TextBox[4];
tb_dynData_Array[0] = tb_dynData0;
tb_dynData_Array[1] = tb_dynData1;
PC pc = this; //Tried adding this to get past problem but it's not turned out useful
//I think the way I access parent class from child is the problem of why flow in
//parent class isn't reaching overridden method in child when called:
baseInst.addDynamicDataTextBoxes(tb_dynData_Array, lbl_dynData_Arr, childDllName, pc);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{ //I added more info here, but it's probably too much info 3/7/2013
Console.WriteLine("Ko PC::ValidateDynData");
result = -610;
//AT
if ((Convert.ToInt16(tb_dynData_Array[0].Text) >= 1) && (Convert.ToInt16(tb_dynData_Array[0].Text) <= 99))
result = 0;
//VL
if (result == 0)
if ((Convert.ToInt16(tb_dynData_Array[1].Text) >= 69) && (Convert.ToInt16(tb_dynData_Array[1].Text) <= 100))
result = 0;
else
result = -610;
}
In my GenericPC.cs of the parent class:
**Note 3/8/2013: GenericPC is in the Generic visual studio project.
**Note 3/7/2013 When the child class calls the parent class to initialize important data, the parent class shows it's form and fields (I think resume layout shows it). Next, we enter data on the form, including Ko's custom data, then we hit a button on the form (btn_Lock_Config_Click) and it needs to process and validate it's data. I added more methods to get the feel for flow. There are a ton more methods in parent than child (not shown), including try/catch, etc.
//base
public partial class GenericPC : UserControl
{
//class variables (wave your hands..too much info)
public Control GetPC(USB_Comm.CB cbInstance, string dllSelected, TemplateHApp.Templates.TEMPL[] template, string dll, SC.SC.SITE c0, int slaveIndex, int boxID)
{
cb = cbInstance;
SlaveIndex = slaveIndex;
createControls();
itsDll = dll;
templateArr = template;
return this; //return the control for the control array
}
//called from child class
public void setProgramName(string name)
{
Console.WriteLine("Generic setProgramName slaveIndex:" + SlaveIndex);
lbl_Program_Name.Text = name;
}
//called from child class
public void setDTF(string theDTF)
{
Console.WriteLine("Generic setDTF slaveIndex:" + SlaveIndex);
lbl_Program_Name.Text += " ";
lbl_Program_Name.Text += theDTF;
lbl_Program_Name.Refresh();
}
public void addDynamicDataTextBoxes(TextBox [] tb_dynData, Label [] lblTitle, String childName, Object child)
{
childHasDynamicData = true; //somebody's knocking
itsChildName = childName; //child name isn't turning out to be useful here
itsChild = child; //child isn't turning out to be useful here
Console.WriteLine("Generic addDynamicDataTextBoxes slaveIndex:" + SlaveIndex);
//Display what child wants
for (int i = 0; i < tb_dynData.Length; i++)
{
//assumes calling code knows real estate and planned for it
gb_dynamicData.Controls.Add(lblTitle[i]);
gb_dynamicData.Controls.Add(tb_dynData[i]);
}
itsEnteredDynamicData = tb_dynData; //nothing entered yet
}
private void btn_Lock_Config_Click(object sender, EventArgs e)
{
int status = 1;
Console.WriteLine("Generic btn_Lock slaveIndex:" + SlaveIndex);
//it does some flagging and data checking, etc.
status = processDynamicData();
}
private int processDynData()
{
int returnCode = 0; //I'm setting it to desired value for example
//processes data, puts it into data arrays, etc,
if ((returnCode >= 0) && childHasDynamicData)
ValidateDynData(itsEnteredDynamicData, ref returnCode);
//start here for problem...it never calls child method, as intended
}
public virtual void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
Console.WriteLine("Generic::ValidateDynData passing off to child to validate special data");
}
Any ideas why it's not going to the child class implementation of ValidateDynData when I call ValidateDynData in my parent class? This is the only area in my code where I am trying to have a child class override a parent implementation, so I'm not sure if I'm doing something wrong?
I checked the correct version of Generic.dll is referenced in the child's project/class. I did a clean build in the child class. Any other binaries that should be checked? Is there something wrong with my reflection? Is there something wrong with my virtual/override use for ValidateDynData?
Update:
I've been looking at the code some more, and I get flow into the parent class by creating an instance of the parent/base class. So I think that's why I'm not getting into ValidateDynData that is overridden in the child class when I call it in parent. Is there another way to get to the parent's method without creating an instance of the parent?
GenericPC baseInst = new GenericPC();
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
**Update 3/7/13:
It's also possible that the problem is that I press a button on the parent's form which starts a new thread and by doing this, it doesn't know about child class, so that's why flow doesn't get to child when I call ValidateDynData method.
Short answer: Just delete all that awful code and start over.
Longer answer:
// (1)
public partial class PC : GenericPC
{
// (2)
GenericPC baseInst = new GenericPC();
public Control GetPC(…)
{
…
// (3)
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
// (4)
…
}
}
Comments to marked lines of code:
At this point you declare PC as a descendant of GenericPC. So far so good.
Here you declare and instantiate a completely disparate instance of GenericPC which has nothing to do with the instance of PC you are working with.
You call GetPC, a method of an instance of PC, which in turns call GetPC in that completely disparate instance of GenericPC; nothing in common with the original PC instance!
Finally, you expect control flow to end up the original PC instance; but that won't ever happen when, effectively, you all the time call methods of some silly GenericPC instance!
My recommendation is reading a book about object-oriented programming, that provides samples in C#. It seems you are even missing the point of inheritance, one of the basic concepts in OOP.
To fix it, you need to remove the declaration of baseInst, and replace all calls to baseInst's methods with the base keyword. Then your code will actually call methods declared in the ancestor class within the same instance. Also most methods shall be declared as virtual in GenericPC and you have to override them in PC.
public partial class PC : GenericPC
{
public override Control GetPC(…)
{
…
return base.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
…
}
}

Hiding Title FIeld in Sharepoint not working

I am trying to do the following to hide the title field from the new and edit form but its still visible.
pls help
/// <summary>
/// Adds source list and content type.
/// </summary>
/// <param name="currentWeb"></param>
private void AddSourcesList(SPWeb currentWeb)
{
currentWeb.AllowUnsafeUpdates = true;
#region Add Source content type.
if(currentWeb.ContentTypes[SponsoringCommon.Constants.CONTENTTYPES_SOURCES_NAME] == null)
{
#region Hides title column
currentWeb.Lists.Add(SponsoringCommon.Constants.LISTNAMES_SOURCES_NAME, string.Empty, SPListTemplateType.GenericList);
SPList sourceList = currentWeb.Lists.TryGetList(SponsoringCommon.Constants.LISTNAMES_SOURCES_NAME);
SPField titleField = sourceList.Fields.GetField("Title");
titleField.Required = false;
titleField.ShowInEditForm = false;
titleField.ShowInDisplayForm = false;
titleField.ShowInNewForm = false;
titleField.Hidden = true;
titleField.Update();
#endregion
I cannot see the rest of the code, but I had similar problem, and the thing I was missing is to .Update() the List and the Web. So in your case try to update sourceList and at the end currentWeb.
Hopefully, it will help solve your problem.

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