I'm binding my array of a abstract type with no problems to the datagrid. However, I just learned that a new property will be added and it's of type IEnumerable. I'm going to assume that the public properties of it are of type String.
How can I databind that new property so it displays anything useful in the datagrid? Testing a fake addition gives me only empty fields in that column. I can't split the new property into several columns because the count may vary.
Is it possible to achieve without explicit binding method at all?
I've got some hits when I searched but none of them gives me a clear answer. Possibly I'm just missing it due to confusion.
Related
I have created a control derived from a WPF ListBox that allows me to reorder the contents of the ListBox by dragging and dropping. I do this with the below code:
ListBox.Items.RemoveAt(sourceIndex);
ListBox.Items.Insert(targetIndex, droppedObject);
The problem shows up when I bind an ObservableCollection to this derived class's ItemsSource. When bound, an exception is thrown when I try to access the ListBox.Items and edit it. It instead wants me to edit the ObservableCollection instead. This makes sense to me, but I don't have access to this collection in the .cs file of my derived ListBox class. Since the implementation of my derived control should be generic, I shouldn't ever access a global ObservableCollection within it. I have attempted to access the ListBox's ItemsSource and try and do my updates to it, but I cannot seem to cast it into a list that allows me to easily edit it without knowing what the contents are. Is there an easy fix to this issue that I am missing?
but I cannot seem to cast it into a list that allows me to easily edit it without knowing what the contents are
You need to make sure that the type assigned to the ItemsSource property actually supports re-ordering of items, i.e. that it implements the IList interface. Otherwise you cannot use the RemoveAt and Insert methods.
Cast using the as operator:
var sourceCollection = ListBox.ItemsSource as IList;
if(sourceCollection != null)
{
sourceCollection.RemoveAt(sourceIndex);
sourceCollection.Insert(targetIndex, droppedObject);
}
If you get a null reference back, it means that the source collection doesn't implement the IList interface and you cannot move an item based on an index.
Yes, the correct way to do it is to actually reorder items in the underlying ItemsSource. I mean, you can coerce ListView to apply its own ordering (e.g. binding ItemsSource to a custom CollectionView instead), but things will get very messy when underlying collection changes. Personally, I'd avoid that route.
The proper answer would depend on why exactly do you want to order items and whether the ViewModel and Model layers should react to this reordering somehow (e.g. save the new items layout somewhere so it won't disappear after application is restarted). Normally, ViewModels are not expected to listen on changes to their ObservableCollections, but would rather accept 'MoveUp'/'MoveDown' commands from view and alter ObservableCollection accordingly.
On the other hand, if you're not creating an externally reusable library, and can guarantee that your ViewModels will not freak out if View starts to actually moving items around bound collection, its a relatively safe bet to just cast ItemsSource to non-generic IList interface and manipulate the items directly, as you suggested. Note that theoretically a bound collection may not implement IList, but in a real world application it almost certainly would.
I know this is a pretty broad problem, so I'm surprised I haven't found a good answer yet. Here's my situation:
I have a class named TimeConverter that I use quite often, which implements the IValueConverter interface converts a string containing an amount of time (such as "25:36") into an integer representing the number of minutes (which for the earlier example would be 1536). Currently, when someone enters something untranslatable (like "asdf") the converter returns DependencyProperty.UnsetValue, which causes the bound element (usually a TextBox) to show a red border. Here's the problem, the class containing the integer property on the other end of the binding needs to know that there is a conversion error.
I've found this to be quite difficult and almost impossible to do without the data item having a reference to the bound TextBox. If I get a reference to the TextBox, I can use the Validation attached properties, but i feel like that's sloppy and its also not always possible. Currently I have one of these bindings in place on a TextBox, inside a Setter, inside a Style, inside a DataTemplate (pretty far removed from the visual tree), which also prevents me from using the Validation.Error even for notification. And of course the simple answer of binding Validation.HasError to the data item doesn't work because of how the property is declared.
So how CAN I notify the data item when the conversion fails?
I'm new to Silverlight 4 and having a tough time googling this one since I'm not terribly familiar with the terminology involved. Can someone point me in the right direction?
I have an observable collection that I want to represent in an ItemsControl list. The type of the collection is a class that- for simplicity's sake- let's call PersonInfo. Each PersonInfo has a string property Name and an observable collection PhoneNumbers. Everything works fine when I tell the ItemsControl's DataTemplate to use "UserControl1" for visualizing the data- the bindings work.
My problem is that- for this theoretical example- I want to base the control used to display the PersonInfo on certain values in the Name propery. So I want to use UserControl1 for any entries named "Joe", and use UserControl2 for all others. I've found IValueConverter stuff, but that doesn't seem to help with selecting the control type used to visualize the data.
Sidenote: UserControl1 and UserControl2 show data in a similar way, but there are some differences within their complicated grid layouts that forced me to create 2 separate usercontrols. If anyone knows how I could build multiple layouts into UserControl1's xaml and then switch between them at runtime via a property binding, that would probably let me sidestep this issue altogether...
Can anyone recommend a general strategy for solving either side of this problem?
Thanks in advance!
I’ve solved a similar dilemma by using an IValueConverter in an unusual way: I created a "VisibilityConverter" that tells a control whether it ought to appear. In the case of your example you would have two of them: one Convert method would
return ((PersonInfo)o).Name == "Joe" ? Visibility.Visible : Visibility.Collapsed;
and the other would do the opposite. Then bind UserControl1's visibility to one VisibilityConverter and bind UserControl2's visibility to the other and violà, they swap out based on the data.
I want to have an empty item in the comboBox to allow the user to "Unselect" and keep the comboBox empty (Null value).
How can I do that?
Make your life easier by using a sentinel value. That is, an instance of your view model class that represents nothing.
If you take a look at my blog entry here, you can see a binding solution that doesn't require you to "modify" your VM or to add dummy items into a collection that doesn't really fit with your data.
Basically, you use a CompositeCollection in your XAML, which gives you the ability (for instance) to have numeric values in your combo-box, and the text "Please select..." to designate the place holder, which you can't do if you are binding entirely to numeric fields in your model and relying on that to add this magic value.
We are using the standard method for our controls to report broken BO rules. This is done via the interface IDataError in our BO’s and in XAML the control is bound to the BO’s property etc. This approach works OK. But we need to show 2 types of visuals in the UI depending on the type (or category if you like) of the invalidation error. If it’s a required field then we show a CueBanner (water mark) but for other types we change the colour of the controls boarder. In both scenarios we set the tool type of the error message.
The Problem with IDataError is that it doesn’t support a method/property to distinguish between error types.
The only way I can do that is by examining the error text, required field text must contain the key word “required”. The following approach doesn’t feel right but it’s the only way I can determine the type of error and then deal with it accordingly. All required field rules must have as part of the error text “required field”.
To make this all work I have created a custom dependency property called ErrorMessage. In my ResourceDictionary I have a Style.Trigger for Validation.HasError. In there I set my dependency properties value to the ErrorContent. Now when my dependency properties value changes I can examine the text and set the Validation.SetErrorTemplate( myControl, newErrorTemplate) to the template to suit the error type. I have to wire up a few events to the control such as lost and got focus to manage removing or adding the cueBanner template but the whole thing will work. It’s just that I’m not sure it’s the best way to do it.
PS. When I set the ErrorTemplate i’m doing this in code, thats building and adding it. Is there a way to point Validation.SetErrorTemplate to a static resource keeping in mind that I need to switch between at least 2 types?
Your thoughts please..
Would it be possible to derive an interface IDataError that adds an extra property which is an enumeration of the error type. Then you could try and bind against it.
If you're okay with an (untested)approach that suffers a little bit of clarity, then you could do the following:
throw an exception instead of returning an string with the IDataErrorInfo Interface. In your ErrorTemplate, you can access the ValidationErrors (and the ValidationError.Exception Property).
Then, you use a DataTrigger on the Exception in combination with a converter, that checks for the right Exception-Type and return true or false. It should be enough to do the job.