I'm using a DCV as a property in the View Model.
Everything works fine but what about custom sort?
Say I have a string property in my model which should be sorted alphanumerically.
How can I achieve such thing?
UPD:
Model:
public class MyModel
{
///...
public SomeProperty {get;set;}
}
xaml:
<data:DataTextColumn Binding={binding path=SomeProperty}, canusersort=true />
When sorting within the datagrid, the property gets sorted with disregard to alphanumeric order, i.e. in a regular string way. I'd like to apply my custom sort, e.g. by introducing my own IComparer. No API is available at least as I know of it.
Any clues?
The DomainCollectioView has special collection:
SortDescriptions
You could add next code in Your ViewModel:
DCV.SortDescriptions.Add(new SortDescription("SomeProperty ", ListSortDirection.Ascending));
Related
My application uses the MVVM pattern. My TextBox is bound to a property of my ViewModel (type string).
When ever the content of the TextBox changed via the user typing, I want to perform some validation.
So, currently, my code is
<TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}" />
and my ViewModel has this property and field:
private string _xmlContentAsString;
public string XmlContentAsString
{
get { return _xmlContentAsString; }
set
{
if (_xmlContentAsString == value)
return;
_xmlContentAsString = value;
PerformValidiationLogic(value);//This is where I am unsure
}
}
Now, this works but, and I don't know why, I don't like this! It some how feels 'hacked' to include the method in the property.
Can some one please tell me if this is the correct approach when using the MVVM pattern?
There's different type of validations.
For simplistic validating string lengths or allowed characters etc you can use DataAnnotations and put the validation in attributes on your properties. You'll need to include
using System.ComponentModel.DataAnnotations;
then for example to keep string to 9 characters:
[StringLength(9)]
public string StringValue
{
get
{
return stringValue;
}
set
{
this.stringValue = value;
}
}
Then there is validation that is a bit more complex and is effectively enforcing your business logic.
There seem to be many views on how to do this. Ideally it should belong on the model, so that the validation can be reused, but obviously called via the viewmodel.
Personally I will put method calls in the property setters occasionally, to me thats the whole reason for having the ability to create setters and getters - otherwise there's very little point in having anything other than auto properties.
But if it's complex or asynchronous then you can hit issues.
I'd be very careful doing it with UpdateSourceTrigger=PropertyChanged, as that means you'll be firing it every character.
In your example, you perform validation logic on the value, but what would be the result of the validation if it fails? Typically you would want to notify the user of a validation failure. If that is the case, then I suggest IDataErrorInfo (examples can be found here:
http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/).
If you plan on overriding the value without notifying the user, then validating in the setter is acceptable (though still not a fan for more personal reasons).
In my opinion thats the correct approach. I would write a base class for your ViewModel that contains a method that sets the property, call PropertyChanged and validate if some validation rule is attached to that property.
For example:
public abstract class ValidableViewModel
{
private List<ValidationRule> _validationRules;
public ValidableViewModel()
{
_validationRules = new List<ValidationRule>();
}
protected virtual void SetValue<T, T2>(Expression<Func<T>> expression,
ref T2 backend, T2 value)
{
if (EqualityComparer<T2>.Default.Equals(backend, value))
return;
backend = value;
OnPropertyChanged(expression);
Validate(expression.Name, value);
}
protected void Validate(string propertyName, object value)
{
foreach(var validationRule in _validationRules)
{
if(validationRule.PropertyName == propertyName)
validationRule.Execute(value);
}
}
}
The code is not complete, there is missing a lot. But it could be a start ;-)
I personally don't advise putting so much logic in your property. I would use a command bound to an event, ie the lostfocus event of the textbox, and perform your validation there.
I would use something like this:
<TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="LostFocus">
<interactivity:InvokeCommandAction Command="{Binding LostFocusCommand, Mode=OneWay}"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>
then have a command in your view model that is LostFocusCommand wiht your validation logic.
I use mvvm-light and can give a more detailed example for that. (you will need to include the blend interactivity declaration at the top of your xaml)
I am using the extension News System, "news", and while changing the templates, I've noticed that while I can use things like {newsItem.datetime} or {newsItem.uid}, I cant use this with the custom fields i have created when extending the table tx_news_domain_model_news, like {newsItem.mycustomfield}
Edit: I have been pointed to this url and I've followed the instructions, but it's not working. This is my code
News.php
<?php
class Tx_WedoExtendnews_Domain_Model_News extends Tx_News_Domain_Model_News {
/**
* #var string
*/
protected $txWedoextendnewsLocation;
public function getTxWedoextendnewsLocation() {
return "this";
return $this->txWedoextendnewsLocation;
}
public function getWedoextendnewsLocation() {
return "that";
return $this->txWedoextendnewsLocation;
}
}
?>
Since I wasn't getting anything, I changed the returning values to string literals, to see if the problem was in the class and method names, or the property. Im still not getting anything. I think the underscored might be playing tricks on my code.
My extension key is wedo_extendnews and the new field is tx_wedoextendnews_location. Any ideas where the error lies?
Yes. To be able to access an object in fluid, you need the according setters in your model and maybe (not sure right now) an entry in the TCA.
If you want to access {newsItem.mycustomfield} you need an according setter in the model, like public function getMycustomfield() (note the get in get<Myfuncname>, it is mandatory).
When I use database first, after creating the edmx file, all the conceptual models have already been generated. But I want to do some special operations on certain fields. For example, there's a field named 'price'; I want the matching property 'Price' to return double of the 'price'. How can I do that? If I modify the getter in the code, every time I update the model from database, all of the modifications go away.
What's the correct way to do this?
What you can do is create a partial class for entity which contains the Price Property and put a getter like this (A property with double price will be meaningful ),
Public partial class YourEntity{
Public float DoublePrice{
get { return Price*2;}
}
}
Or you can create a class inherited from the entity,
Public partial class Entity:YourEntity{
Public override float Price{
get { return base.Price*2;}
}
}
I have an enum property. I want the serialized XML for this property to be the splitted camel-case string of the enum and vice versa.
I have two functions, one is ConcatCamelCase and the other is SplitCamelCase, I want the serializer to use them accordingly, is this possible by just decorating the field with an attribute?
If no, what are the other option without having to mess with all the other fields?
You'll have to do something like this:
public class SomeClass {
[XmlIgnore]
public MyEnum MyRealProperty {get;set;}
[XmlElement("MyRealProperty")]
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public string MyProxyProperty
{
get {return SplitCamelCase(MyRealProperty);}
set {MyRealProperty = ConcatCamelCase(value);}
}
}
You can explicitly set the name of everything that is serialized using the XMlSerialization attributes.
[XmlRoot("theNameYouWant")]
[XmlElement("theNameYouWant")]
I have looked around a bit for this--can't find the proper collection
Here is the signature of my desired ViewModel. There are some interesting
alternatives out there David Hill's CollectionViewModel or ObservableDictionary(Of TKey, TValue) on codeplex. But for now, I would like a built-in collection (for SL4) that handles this. Thanks
public class myViewModel: INotifyPropertyChanged
{
public ObservableCollection<MyDataType> MyCollection;
private ObservableCollection<MyDataType> _myCollection;
public CurrentItem<MyDataType>() { return _myCollection.CurrentItem;}
public int GetCurrentIndex() { return _myCollection.CurrentIndex;}
public SetCurrentIndex(int Index) { _myCollection.CurrentIndex = Index;}
There isn't a built-in collection that provides this. However, you could just store the currentIndex value as a private int inside your ViewModel, and refer to it for the current index methods, as well as use it for CurrentItem<T>().
But do we really need something like this? You can always bind to "ViewModel.MyCollection/" to get the currently selected item