I have a created a UserControl with a combobox in it. This combobox is populated from a xml, when this is not present, it is loaded from resource file.
It works fine in the program, but it can't be displayed in designer - it says: "Object reference not set to an instance of an object."
In the class responsible for loading the list from xml the null reference check is skipped for reasons beyond my understanding...
public SortedDictionary<string, string> Countries
{
get
{
if (object.ReferenceEquals(countries, null))
{
GetCountryList();
}
return countries;
}
}
Populating of the comboBox goes like this:
comboBoxCountry.DataSource = new BindingSource(Program.language.Countries, null);
Program.language is initialized in Program, but it does not help for the Designer.
The question is, how (when, at what event) should I populate the ComboBox (=load list from xml) to be able to display my control in designer.
If possible, you want to check for this.DesignMode and then simply not load the ComboBox at design-time.
Does GetCountryList() set a member variable? If so, move that call to a method. Property get accessors and the ToString() method are assumed pure: the program state before and after must be identical. Violating this assumption can cause all sorts of problems, especially designer/debugger/runtime inconsistency. Various rants have taken place, but the best thing to do is understand the assumption, follow it, and let it work to your advantage as you debug.
Related
I have a large WPF application that uses the MVVM design pattern and asynchronous data access methods. It uses the old style asynchronous code with callback handlers and the IAsyncResult interface... here is a typical example:
function.BeginInvoke(callBackMethod, asyncState);
Then , in the view model, I have the following callback handler:
private void GotData(GetDataOperationResult<Genres> result)
{
UiThreadManager.RunOnUiThread((Action)delegate
{
if (result.IsSuccess) DoSomething(result.ReturnValue);
else FeedbackManager.Add(result);
});
}
The RunOnUiThread method is basically the following:
public object RunOnUiThread(Delegate method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
This problem only affects one view model, the one that enables the users to edit the Release objects. On the related view, certain collections that populate ComboBoxes are requested from the database when it is first loaded. Let's simplify this saying that there is just one collection called Genres. After the data arrives in the view model, it is handled like so:
private void GotGenres(GetDataOperationResult<Genres> result)
{
UiThreadManager.RunOnUiThread((Action)delegate
{
if (result.IsSuccess) Genres.AddEmptyItemBefore(result.ReturnValue);
else FeedbackManager.Add(result);
});
}
When the collection is present and a Release object has been selected in the UI, I have the following code selects the current Release.Genre value from the collection:
if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id))
Release.Genre = Genres.GetItemWithId(Release.Genre);
At this point, I should note that this all works fine and that this is the only line that references the Release.Genre property from the view model.
My particular problem is that sometimes the Release.Genre property is set to null and I can't work out how or from where. >> Edit >> When I put a break point on the property setter, << Edit << the Call Stack provides no real clues as to what is setting the null value, as there is only a [Native to Managed Transition] line. On selecting the Show External Code option from the Call Stack window, I can see basic asynchronous code calls:
Now I can confirm the following facts that I have discovered while attempting to fix this problem:
The one line that references the Release.Genre property is not setting it to null.
The call to Genres.AddEmptyItemBefore(result.ReturnValue) is not setting it to null... this just adds the result collection into the Genres collection after adding an 'empty' Genre.
The Release.Genre property is sometimes set to null in or after the call to Genres.AddEmptyItemBefore(result.ReturnValue), but not because of it... when stepping through it on a few occasions, execution has jumped (in an unrelated manner) to the break point I set on the Release.Genre property setter where the value input parameter is null, but this does not happen each time.
It generally happens when coming from a related view model to the Release view model, but not every time.
The related view model has no references to the Release.Genre property.
To be clear, I am not asking anyone to debug my problem from the sparse information that I have provided. Neither am I asking for advice on making asynchronous data calls. Instead, I am really trying to find out new ways of proceeding that I have not yet thought of. I understand that some code (almost certainly my code) somewhere is setting the property to null... my question is how can I detect where this code is? It does not appear to be in the Release view model. How can I continue to debug this problem with no more clues?
I usually use Flat File, XML or Database logging for debugging purpose. I created those Log classes for logging purpose, so that I can call it from every applications I develop.
For database logging, you can do it as simple as:
void WriteLog(string log){
// Your database insert here
}
Maybe you need datetime and other supporting information, but it's up to the developer. For simple flat file logging is:
void WriteLog(string log){
using(TextWriter tx = new StreamWriter("./Log/" + DateTime.Now.ToString() + ".txt", false)){
tx.WriteLine(log);
}
}
You can use the logging in your application in both ways:
1: Method call
WriteLog((Release.Genre == null).ToString());
if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id))
Release.Genre = Genres.GetItemWithId(Release.Genre);
2: Add it in your Release.Genre set (or get) property
public class Release{
private Genre _genre=null;
public Genre Genre{
get{
WriteLog((_genre == null).ToString());
return _genre;
}
set{
WriteLog((_genre == null).ToString());
_genre = value;
}
}
}
With this, you can try to get the call sequence, whether the Release.Genre is being set in other places before, during call, etc.
Please note I just giving the general image of building logging. Please expect errors. However, it is developer's responsibility to develop the Logging acitivities to meet requirement.
I got a problem with ListView in System.Windows.Forms, that i can't handle it on myself, begging for help or a hint where do I do wrong?
Description:
- I have a class - name it cListViewItem ('c' from custom), that inherits from standard ListViewItem, but stores my own data handling class. Now, after adding cListViewItem to a ListView class using ListView.items.Add( ) i don't seem to have any control over the item's name.
- fragments of my source (lil changed for the purpose of this post)
using System.Windows.Forms;
cListViewItem:ListViewItem
{
// gives a basic idea
public cListViewItem( myclass DataStorage )
{
// constructor only stores DataStorage to a local variable for further use;
this._storage = DataStorage;
}
protected myclass _storage;
// and there goes the fun:
// I thought that ListView class uses .Text property when drawing items, but that is not truth
// my idea was to 'cheat' a little with:
new public String Text
{
get
{
// overriding a getter should be enough i thought, but i was wrong
return( some string value from DataStorage class passed via constructor );
// setter is not rly needed here, because data comes from this._storage class;
// in later stages i've even added this line, to be informed whenever it's called ofc before return( ); otherwise VisualStudio would not compile
MessageBox.Show( "Calling item's .Text property" );
// guess what? this message box NEVER shows up;
}
}
}
I see that's important to use .Text setter, but constructor is the last moment i can do it, right after creation cListViewItem is being added to ListView Items property and displayed, so there's no place to call .Text = "" again.
My piece of code only works when I set all things in cListViewItem 's constructor like:
public cListViewItem( myclass DataStorage )
{
this._storage = DataStorage;
this.Text = DataStorage.String1;
// and if I add subitems here, I will see em when the ListView.View property be changed to View.Details
}
So am I blind or what? when I use cListViewItem.Text = "string" I will see 'string'
in the ListView but when I just override .Text getter i can't see the items :(
ListView class gives the flexibility of showing items the way I need. I wanted to create a class that will bind my custom data storage class with a ListView class. In the next stage of my application I want to bind a form for selected item in a ListView, that will allow me change item's (my custom class) values. That's why i wanted to make each ListViewItems item remembering corresponding custom data storage class.
Names shown in ListView will never be uniqe, so multiple same names all allowed, but items will differ by a id value (database-wise);
I just can't figure out why using ListViewItem.Text setter does the job, altho ListView class does not use ListViewItem.Text getter for displaying items (my MessageBox never pops up)??
Pls help.
The main problem here is that you are hiding the property with the new keyword. The original property is not virtual ("overwritable") so it is NOT overwritten but shadowed.
Read here for more information.
If I understand correctly, then the following points might be helpful.
For storing custom data you don't actually need to derive from the ListViewItem class, instead you can use an instance of a ListViewItem and set the Tag property to any object, this can be your DataStorage class. If you do this, then after you've constructed the ListViewItem set the Text of it
DataStorage storage = GetDataStorage();
ListViewItem item = new ListViewItem(storage.Name);
item.Tag = storage;
If you are going to inherit the ListViewItem then set the value in the constructor
public cListViewItem( myclass DataStorage )
{
// constructor only stores DataStorage to a local variable for further use;
this._storage = DataStorage;
this.Text = this._storage.Name;
}
Property and Method hiding gets a little confusing for myself at least, I can't quite remember the rules, but ultimately the call to Text that is done automatically is not going to be calling your version...
I got to think I don't understand how it works.
My specific question is: Why am I allowed to set the value of a list property element when I have no setter and no backing list variable?
Let me explain. Let's say I have a CustomerTable class with:
public List<string> Name
{
get
{
var names = new List<string>();
foreach (CustomerRow row in Rows)
{
name.Add(row.Name);
}
return names;
}
}
The idea is to have a read-only property show the contents of a column without duplicating data in my class, since I already have a list of rows.
Anyway, my surprise comes when pieces of code like the following one are accepted by Visual Studio without claiming any kind of error (and it even allows me to compile without errors):
Name[0] = "John";
I can't understand why this is legal. My property has no set { }, and it doesn't even have a backing list to modify. What is this piece of code supposed to do?
Shouldn't it work like a method? Is there really a stored list other than the one I generate each time someone "gets" it?
(I can give more details on demand and will also be grateful for any other remarks)
You are not setting the property, rather you are getting the property (which is a list) and then operating on it (in your example, changing its first member). If you were to try:
Name = new List<string>();
You would get the compilation error you were expecting to get. Note that since you are creating a new list every time, your Rows property remains read-only (assuming it is not exposed somewhere else). If you want to make it clear that changes to your returned collection are meaningless, you can change the type of the Name property to IEnumerable<string>:
public IEnumerable<string> Name
{
get
{
return Rows.Select(row => row.name); //LINQ is more elegant here
}
}
In your example you don't set Name (which is read-only, indeed), but you set the first list element contained in Name, which is Name[0], and there's no reason why you could not do that since List<string> is an object type which allows to set elements.
Is there a way of creating a new setting in the Settings.settings file during run time?
For example, I want to write to the settings file from one class function, and read that value from a different class function. And no, I don't want to pass the values.
I know how to get values from the Settings.settings file
(value = Properties.Settings.Default.XXX)
I know how to update an existing value
(Properties.Settings.Default.XXX = newValue; Properties.Settings.Default.Save())
I want to know how I can add "Name", "Type", "Scope" and "Value" into the Settings.settings file during run time.
Any suggestions would be appreciated!
Thanks,
Ivar
The Issues
I believe Visual Studio generates code when you design the application settings and values, therefore at runtime this would not be easy and at worst impossible without a designer. However you can sometimes call upon design features at runtime.
You'll notice the code-behind has the properties in C# that you create in your designer. For example, I added a setting for:
Age [int] 30.
The code-behind has generated:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("30")]
public int Age {
get {
return ((int)(this["Age"]));
}
set {
this["Age"] = value;
}
}
(The code generation is why you have strongly-typed settings)
I'm unsure if you could effect this same thing at runtime. You would have to generate code and feed it back to the JIT compiler dynamically or something like that. Or maybe there's another way I don't know about in my limited understanding of settings.
Suggestion/Workaround
I'd suggest figuring out an alternate/easier way instead of jumping through hoops. For example, make one setting a collection type that is serializable so it can store multiple values.
Then you can, for example, store multiple ages under just one setting:
Ages [System.Collections.ArrayList] {add multiple values programatically}
You might end up with C# code to manage it like:
System.Collections.ArrayList list = new System.Collections.ArrayList();
list.Add("1");
list.Add("30");
Properties.Settings.Default.Ages = list;
Properties.Settings.Default.Save();
Here's my scenario - I am working with SL3 (and WCF Data Services) and I have a custom form that manages Employees. On the form, I have some simple TextBox(es) and some ComboBox(es) for entering basic information for an Employee. In my architecture, I have some base classes, one to handle the Collections of objects (ObservableCollection and INotifyPropertyChanged implemented) and one that is for the Entity (catches and calls OnPropertyChanged("prop"). In my code behind file (.cs), I have an event handler that handles the _SelectedItemChanged() for the ComboBox(es), for example, EmployeeType, where in the database, values might be like Director, Staff, Reporter, Manager, etc. for the Code column (other columns exist in the EmployeeType table like Description, ModifiedDate, and ID). I have some constructors on my form control, and when I load the form with an empty constructor and thus nothing is loaded (which is the way it should load and correct), everything works perfectly, i.e. I can enter data like FirstName (TextBox), HireData (TextBox), and EmployeeType (ComboBox). The issue I am having is when, I am loading this form, and I know the EmployeeType before-hand, so I don't know how to set the ComboBox's SelectedItem programmatically?
I tried something like this, say I want the form to load the EmployeeType as Manager, so I have in my Load() method:
private SetEmployeeType()
{
var employeeType = new EmployeeType { Code = "Manager" };
this.EmployeeTypeComboBox.SelectedItem = employeeType;
}
But as I'm tracing through my code (F5), I see employeeType as an EmployeeType, but it's properties not fully populated (all blank except for Code as I explicitly called "Manager" above), so when my _SelectedItemChanged() event is called, the .SelectedItem = null, and thus the ComboBox is loaded with nothing picked (the ItemSource is bound to a list and it does come through properly).
FYI, I have other methods where I load my list of EmployeeTypes, e.g. GetEmployeeTypes() and that loads fine. If the ComboBox is blank and then I pick a value, the correct value is submitted to the database, but like I noted, sometimes I want to pre-define the SelectedItem and thus disable the ComboBox to disallow the User from entering invalid data.
I even tried some LINQ like so and it seems not to work:
var type = from e in employeeTypeList // collection loads fine with 10 items
where e.Code = "Manager"
select e;
When I trace through the above query, the 'type' does come back with the correct EntityType object with all of the properties populated (count=1 which is correct), but it doesn't seem to bind to the ComboBox since the ComboBox's SelectedItemChanged() is expecting something like this:
var employeeType = this.EmployeeType.SelectedItem as EmployeeType; // i.e. expecting EmployeeType
but instead, my LINQ query brings back a value of something like:
IEnumerable<EmployeeType> // with some extra stuff...
PS. I am working off from memory since I am currently at home and this is from my code at work, so please excuse me if I am missing something obvious. I have tried different scenarios, and just can't seem to figure it out. Thanks in advance for any assistance!
It sounds like you want to set the selected item to be the manager.
If so, you want something like this:
var type = (from e in employeeTypeList
where e.Code = "Manager"
select e).FirstOrDefault();
EmployeeType.SelectedItem = type;
Your code is creating a list of managers, which even though it has only one item, does not match the data type expected by SelectedItem. The solution to this is to just extract the one item from the list using FirstOrDefault which will give the first item in the list or null if the list is empty.
Try to set the mode to TwoWay instead of Oneway if you have set so.