Implement a WPF databinding source with dynamic members/properties simply? - c#

I am working on a project which allows tagging of directories. As part of the interface, I would like to display a list of the directories. Each entry in the list would be the directory name, plus a number of columns. One for each tag known to the application at the time, with a checkbox indicating whether the directory has been tagged with that tag or not. The user can then tag or untag a number of directories easily.
I thought using a WPF DataGrid would be good for this, but am having trouble deciding how to store the tagged directory in a way that allows me to bind it to the DataGrid instance easily, since the number & makeup of the tags could change at any time.
One way would be to have a master list of directories & their tags, and from this I could generate a complementary set of Expando objects every time the number of known tags changed. Each object would have a boolean property for each tag. The list of these objects could be bound to the DataGrid and autogenerated columns would display them automatically. The nice thing about this is that it does model what I am displaying nicely - even if the directory doesn't have a tag, it still has the property of "doesn't have this tag", and its simple to implement. The problems are its messy and inefficient, and (not sure about this) I don't think I can call methods on the Expando object when the properties change.
The other way would be to dynamically re-create a DataTemplate whenever the known tags changed. The downside is I have to dynamically create a DataTemplate in code-behind.
I wonder though thinking about the first option - is there a way to override the properties an object appears to have to WPF?
For example, is there an interface like IDataBindingSource which looks something like
interface IDataBindingSource {
string[] MyProperties();
Type[] MyPropertyTypes();
object[] MyPropertyValues();
}
That is, is there a simple way to change what properties appear to the DataGrid (and so use autogenerated columns) at runtime?
EDIT: To clarify about the tags. By tags I mean the small descriptive string version. The number of tags the user will want is limited, but there are a large number of directories. So I would like to display a set of checkboxes for each directory that would allow me to add or remove a tag for that directory, just like you would set permissions for users, for example (each permission being a tag, user's the directory). The number of potential tags at any given time though is variable, as the user could add more, or remove a tag from all directories and effectively deleting it.
This isn't a hard problem - a really naive way would simply be to manually draw a table, one column for the directory, the others with the known list of tags, and then logic would create and set checkboxes in the cells with loops. There are many ways to do it - but I would like to use the nicest - that allows me to code it quickly and preserves functionality inbuilt into controls like freezing and reordering, etc.

I've never been a fan of the DataGrid control, especially not in WPF. Considering how versatile WPF is with control templating and styling, I'd go with the ListView using a GridView as the content (ListView.View).
Then you can scrap the whole convoluted IDataBindingSource bit and go straight MVVM, which is much easier with standard bindings.
For example, you could have a DirectoryModel class that would have something like this:
public sealed class DirectoryModel : INotifyPropertyChanged
{
public ObservableCollection<DirectoryModel> Subdirectories { get; set; }
// Notify when this property changes for proper binding behavior!
public bool IsTagged { get; set; }
}
Then your ListViewItem.IsSelected property would be bound to DirectoryModel.IsTagged.

Related

Control.s Tag. When should I use it?

When I see my company working code, I sometimes see the code "Tag" member of Controls. My co-workers use it as a name tag. But the Controls have already a "Text", "Name" thingy properties. When I see the code, It looks fine to call the Controls with other properties.
I feel somewhat the "Tag" property is not for use of only giving the Control a specific name. So I looked up MSDN for information about it.
They say "Tag" is an Object that can store any data like class. And get the data fast from the tag property. I want to know when is the case should a programmer use it for? Can anyone help me with an example situation and codes?
By the way what are those attributes for? It seems those make the tag more special.
[System.ComponentModel.Bindable(true)]
[System.ComponentModel.TypeConverter(typeof(System.ComponentModel.StringConverter))]
public object Tag { get; set; }
The tag can be used for anything you like, common use cases
when a lot of controls share the same click handler
tag on list / tree items that let you associate data with the clicked object (a customer object in a list of customers say)
The name nor text is usable in the second case

HierarchicalDataTemplate - Ignore specific types on generation

My problem is the following: I got a Tree which has an dynamic depth of categories (each category can have sub-categories as well as entries).
Now I added a HierarchicalDataTemplate for the categories to display correctly in the TreeView. But I get a lot of empty entries, which do not apply the Template (wrong type) but show up in the tree as 'corpse'.
How can I ban them from the generation process? Because it's an abstract tree, they are of the same base-class as the categories are. So they get into the tree, because the tree always searches the "Branches"-property which contains either categories, entries or both.
Any ideas? I didn't find any event of the TreeView which probably give me the opportunity to skip various entries during generation nor any option/property of the template to do so.
Detailed Description: I got a generic Tree class. This class has branches of type "A_TreeLeaf" (abstract). The Tree's generic type must inherit A_TreeLeaf of course. My data is structured in categories (CategoryTreeLeaf) and Data (DataTreeLeaf). Each leaf can have sub-leaves (branches), of course.
Now I load my data from a database and build the tree. Each category has X sub-categories. And each category also could contain some Data. This structure helps me a lot, because I got an clear hierarchic structure of categories and data. This way it should be visualized to the user. But I want to separate Data and Categories. The TreeView should show just the categories (by an HierarchicalDataTemplate) and the ListView just the Data (by an DataTemplate). The ListView works fine, but the Tree shows some "corpse"-entries which are the DataTreeLeaf-instances.
I want to filter the DataTreeLeafs on generation or just stop the TreeView displaying them. Is there any "non-hack" solution? I don't want to copy the tree and remove the Data-leaves unless it's really necessary... because this would cause a lot of overhead work to do for me and to manage either the code behind which uses the real tree or the visualization with the fake-tree (because I need to bridge it somehow that it's updated automatically when one of both changes).
You have a unique problem... you have some data items in your hierarchical data that you don't want to display, but for some reason can't remove. If that sums up your problem, then you're doing something wrong.
In WPF, you shouldn't need to hide data items from the UI, instead you simply don't put them into the collection in the first place. It sounds like your process of filling your hierarchical data is flawed and you'd be better off fixing that at the source than trying to deal with the problems that it causes in the UI.
If you can't fix the actual process for whatever reason, then your next best option is to iterate through the data before you display it and simply remove any data elements that shouldn't be there. When using WPF, it is always best to provide your UI with data that fits the purpose.
However, if for whatever reason you can't even do that, then your last option is to simply define an additional DataTemplate for your abstract base class and just leave it empty:
<DataTemplate DataType="{x:Type YourDataTypesPrefix:YourBaseClass}">
</DataTemplate>
Of course, you'd have to define DataTemplates for each sub type, or they'd also be rendered empty.

Programmatically filter custom properties

I have an existing custom control library with controls which may contain properties: HeaderStyle, ModalStyle, Collapsable, etc...
In the user interface the program is currently displaying a categorized list of these properties. I am trying to update this code to hide properties they dont normally use. I have a list of properties to hide/show based on button click but I am not sure how I can hide these fields programmatically.
I would like to retain any values entered into the fields before hiding and re-display the values if the fields are shown again.
Here is a property that current exists but would like to be hidden/shown on toggle.
/// <summary>ModalStyle property for control</summary>
[XmlAttribute]
[DefaultValue(Utility.Common.Enumerations.ModalStyle.None)]
[Category(PropertyCategories.Rendering)]
[Description("Modal dialog style")]
public ModalStyle? ModalStyle
{
get { return control.ModalStyleActive; }
set { control.ModalStyle = value; }
}
My original though was to do some variant on #if DEBUG but use my own Conditional however I was unable to find a way to change my conditionals via button/toggle.
Can anyone please help with a solution to my problem? I have 20-30 controls with 20 to 30 properties that would like to be filtered.
I have two suggestions that, while they may not give you the exact functionality desired, will keep your solution much more straight forward.
First:
Since you are the library developer you should just decide what properties you want other developers to have access to though the IDE properties window. If a property is seldom used or not very useful through the IDE then just place the [Browsable(false)] attribute on it.
Second:
If you really want all properties to be visible in the IDE properties window, but want to give individuals a way of hiding the more advanced (or less used) ones, just throw them all in an 'Advanced' category. The user can then simply collapse that category and forget about them.
Also: Take a look at Oliver's answer to this question:
[how-to-show-or-hide-properties-dynamically-in-the-propertygrid]
I'm not sure to understand what you are trying to achieve.
When you use Attributes, those are static to the class. So, in your case, when you toggle a show/hide on an object, it's on an instance of the object. Also, you cannot change an attribute value at run-time.
Maybe you should try an alternate solution like creating a global
map<pair<type of object, property name>, is shown>
and update that accordingly from your editor.
And if you want to use something like a property grid, you will have a problem since it won't check your map, but it can be fixed. You could create a new class at run-time and make it a proxy to your current instance. (check on the net how to achieve that, but it's quite simple. There are 2 possibilities: compile from a string or use the ILGenerator.
Hope this help.

Custom WinForm ListBox with user-input content

I have a need to provide as options multiple objects from a particular data set, and populate a list so that an end-user can select, none,some, all, or all + possibly missing data fields (user-input).
I originally planned to extend a System.Windows.Forms.ListView to include a whitespace item that contained a checkmark, then specially handle the case where a user had clicked this blank line item.
I would like the ability to remove these user-input line items if possible. I do not have to use a System.Windows.Forms.ListView, but its design seems to best-fit this particular use.
Is there a control with this functionality already , or an attribute of the System.Windows.Forms.ListView I have missed that may handle these situtations?
---Update---
ListBox is changed to System.Windows.Forms.ListView
DataGrid sounds like it would be a good fit; otherwise I'd suggest looking at 3rd party controls.

UI for creating invoices

Currently, I'm in the process of making a custom solution for invoicing. I have created multiple ways for customers to create their template (HTML, Word, LaTex) and get invoices according to their template. However, these invoices are party manually generated.
So, the process is:
Request to create a new invoice
An preliminary invoice is created
The user gets a chance to make changes (i.e. add, remove, change rows)
Create a pdf
Just to be clear, the preliminary invoice does not need to be formatted as the template is, but you should be able to add/remove/change rows and for every cell, indicate whether the value should be visible in the final result.
My problem is that i cannot find a suitable way to display the preliminary invoices. I tried a datagrid (default, telerik, devexpress), but it's too messy. Besides a datagrid, i have no idea what i can use.
What controls can i use best to have a nice and usable UI.
Please don't be like this:
alt text http://bitsandpieces.us/wp-content/uploads/2008/03/imagesapple-20google-20and-20you.png
A typical UI paradigm for this kind of thing is to view it as two separate problems: giving the user a way of viewing the elements that he can modify, and giving him the ability to modify any specific element. You use a list control (ListBox, ListView, maybe TreeView if the elements are organized hierarchically or need to be grouped into categories) to present the elements, and then when the user selects an element the program presents a tabular presentation of field names and editable value controls.
Basically, you're dividing the program's functionality into two categories: stuff that the user wants to do to rows (add, remove, re-order, select) and stuff that the user wants to do to the selected row's elements.
You can mush these two sets of functionality into one if you use a DataGridView, but as you've seen that gets pretty ugly if there's any complexity to the elements you're editing.
Two possible approaches to this: the property-sheet paradigm (select object, right-click, select "Properties", edit values in a modal dialog), or a paradigm where the window's split into two panels, with one being the rows and the other being the details of the currently selected row. There are lots of others.
What is your platform? Winforms? WPF?
What exactly did you dislike about using a datagrid for this? Part of the problem is that whether you like it or not, you're going to be coding a datagrid - you essentially described features of one. If at all possible try to use someone else's datagrid because it will save you a lot of work. Typically, 3rd party datagrids should be fairly customizable, and you should be able to make it look however you want - and take advantage of the built in sorting, editing, grouping, etc. Creating a datagrid-like control from scratch isn't easy and should be avoided if possible.
You don't have to have a plain giant datagrid - you can crate a custom control that displays the invoice formatted however you like, with a live datagrid appearing only where the invoice shows tabular data, formatted to appear as an integral part of the invoice itself.
I'm doing something similar, where the client can edit or even remove the line items for the invoice prior to sending it to the client.
The current app they run their business on is a WebForms Intranet application, so this is an extension to that. So they can add/remove/edit rows fairly easily.
But Egor is right. You're essentially talking about a datagrid no matter what you do. I take it you want something 'cleaner' and more intuitive?
Simplicity is difficult.
I would take a look at what is already out there, especially for invoices, and see how they are doing it.
Not sure how big your company is, but it never hurts to take advantage of the large company applications and user interfaces, the pour thousands/millions of dollars into user interface design and testing.
I would take a look at any of the following (most offer a free trial, or just try searching for screenshots):
www.freshbooks.com
www.invoicera.com
www.getcashboard.com
www.simplifythis.com
Just some ideas ... hope this helps!

Categories

Resources