WPF + DevExpress UpdateSourceTrigger - c#

I would like to add to every control's binding the "UpdateSourceTrigger=PropertyChanged".
I could realize that by just writing for every control:
Text/EditValue/Stuff="{Binding x, UpdateSourceTrigger=PropertyChanged}"
But if possible, I would like to avoid this approach, since it is just redundant xaml code I would have to write over and over again, instead of reusing once piece of code.
A style is not an option, because the object bindings differ from xaml to xaml.
Since DevExpress is in use, we make use of the ExtensionMethod
DevExpress.Mvvm.POCO.POCOViewModelExtensions.RaisePropertiesChanged(this);
But the problem here: Imagine editing a TextEdit (Clicking into the TextEdit, typing stuff) and while the cursor is still in the TextEdit field, call the extension method mentioned above. The TextEdit's EditValue will be reset to the old value, since the PropertyChanged didn't call before.
Is there any way to modify application wide all binding behaviour at once?

Is there any way to modify application wide all binding behaviour at once?
No, different dependency properties have different default values for the UpdateSourceTrigger property, but you could create a custom binding markup extension:
public class PropertyChangedBinding : Binding
{
public PropertyChangedBinding()
:base()
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
}
public PropertyChangedBinding(string path)
: base(path)
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
}
}
...and replace {Binding} with your custom binding across all your XAML files:
<TextBox Text="{local:PropertyChangedBinding x}" />

Related

How do i override a dependency property set in XAML to the value i need to in codebehind

I have a dependency property RecordContainerGenerationMode defined for XamDatagrid , irrespective of what the user sets in the XAML i need it to default to a specific value PreLoad .
How do i accomplish this ? The Xamdatagrid is a infragistics grid which really allow me to hide the dependency implementation.
I tried setting the value in the constructor of the xamdatagrid but the XAML defined value is overwritten onto it.
<Controls:XamDataGrid Grid.Row="1"
HorizontalAlignment="Stretch"
x:Name="gridTrdDetail"
DataSource="{Binding Items}"
SelectedRecords="{Binding SelectedObjects, Mode=TwoWay}"
IncludeDefaultCommands="True"
VerticalAlignment="Stretch"
ScrollingMode="Immediate"
CellContainerGenerationMode="Recycle"
GroupByAreaMode="MultipleFieldLayoutsCompact"
RecordContainerGenerationMode="PreLoad" SelectedSum="{Binding Sum,Mode=OneWayToSource}"
IsSynchronizedWithCurrentItem="True">
and this is how i set it in constructor : -
public XamDataGrid()
{
this.SetValue(XamDataGrid.RecordContainerGenerationModeProperty,ItemContainerGenerationMode.PreLoad);
}
Has anyone run into this kinda issue anywhere?
I'm not sure why you would want to do something like that. Like Anatolii Gabuza said, definite code smell there. It's something you'll need to really rethink.
The way everything gets generated is the control gets constructed (calling default constructor), then the properties in XAML get assigned, then if there are data bindings, the value gets updated at run time.
If you don't want the value to change, the easiest way is just don't expose it! If you need to read the value, maybe you can try a read only dependency property.
If you REALLY want it to expose the Dependency Property, you can set it in the property changed event. But, that kind of defeats the purpose of having a dependency property in the first place.
public static readonly DependencyProperty RecordContainerGenerationModeProperty = DependencyProperty.Register(
"RecordContainerGenerationMode",
typeof(ItemContainerGenerationMode),
typeof(XamDataGrid),
new PropertyMetadata(ItemContainerGenerationMode.PreLoad, OnRecordContainerGenerationModeChanged));
private static void OnRecordContainerGenerationModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
XamDataGrid control = obj as XamDataGrid;
if (control != null)
{
ItemContainerGenerationMode newMode = (ItemContainerGenerationMode)args.NewValue;
if (newMode != ItemContainerGenerationMode.PreLoad)
{
control.RecordContainerGenerationMode = ItemContainerGenerationMode.PreLoad;
}
}
}

To use (DataContext) or not to use

I've got a dilemma regarding the DataContext. Let's inspect the following piece of XAML:
<Window xmlns:my="clr-namespace:MyNamespace.Controls"
... >
...
<my:MyControl Name="{Binding Prop1}" Value="{Binding Prop2}" />
</Window>
Obviously, the Window's code-behind contains something like:
DataContext = someViewModel;
Author's intentions are clear - he wants to bind MyControl's Name and Value to Window's DataContext's Prop1 and Prop2. And this will of course work. Unless. (dramatic pause)
Unless MyControl is a composite UserControl, which also wants to take advantage of short notation of bindings and sets its DataContext to its own viewmodel. Because then it will become clear, that the bindings in Window's XAML actually bind to MyControl's DataContext (previously inherited from Window's one) and now they will stop working (or worse, will keep working if MyControl's viewmodel actually contains properties named Prop1 and Prop21).
In this particular case solution is to bind in Window's code explicitly:
<Window x:Name="rootControl"
xmlns:my="clr-namespace:MyNamespace.Controls"
... >
...
<my:MyControl Name="{Binding ElementName=rootControl, Path=DataContext.Prop1}"
Value="{Binding ElementName=rootControl, Path=DataContext.Prop2}" />
</Window>
TL;DR If we're using short notation of bindings (when binding to DataContext) we may encounter quite tough to nail bugs resulting from bindings suddenly pointing to wrong DataContext.
My question is: how to use short binding notation without risk, that I'll bind to wrong DataContext? Of course I may use the short notation when I'm sure, that I'll be using inherited DataContext and long notation when I'm sure, that control will modify its DataContext. But that "I'm sure" will work only until first mistake, which will consume another hour of debugging.
Maybe I'm not following some MVVM rule? E.g. for example DataContext should be set only once on the top level and all composited controls should bind to something else?
1 I've gone through that, actually. The Window's DataContext contained a property named (say) Prop and the control replaced its DataContext with a class, which also contained a property Prop and everything worked fine. Problem appeared when I tried to use (unconsciously) the same pattern with non-matching property names.
By request:
Fragment of MyControl's code:
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
// Using a DependencyProperty as the backing store for Name. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(MyControl), new PropertyMetadata(null));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(MyControl), new PropertyMetadata(0));
Window's viewmodel:
public class WindowViewmodel : INotifyPropertyChanged
{
// (...)
public string Prop1
{
get
{
return prop1;
}
set
{
prop1 = value;
OnPropertyChanged("Prop1");
}
}
public int Prop2
{
get
{
return prop2;
}
set
{
prop2 = value;
OnPropertyChanged("Prop2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Now assume, that on changing of Name and Value dependency properties, MyControl generates some viewmodel and executes the code:
model = new MyControlViewModel(Name, Value);
this.DataContext = model;
And internal MyControl controls bind to this DataContext.
From now on, the original Name and Value bindings will no longer work.
Unless MyControl is a composite UserControl, which also wants to take advantage of short notation of bindings and sets its DataContext to its own viewmodel.
And that's where I stopped reading. This is, imho, a MVVM anti-pattern.
The reason for this is twofold. First, you screw with anybody who is using the control. "Hey," you say, "you can't bind your stinky VM to my beautiful UI. You have to use MY custom VM!" But what if your VM is hard to use, lacks logic or features needed by the overall application? What happens when, to use your UI, we have to translate our VM/models back and forth with your VM? Pain in the butt.
Second is that your custom control is UI. Its logic is UI logic, and so it is unnecessary to use a view model. It is better to expose DependencyProperties on your control and update your UI as necessary. That way anybody can bind to your UI and use it with any model or view model.
You can solve your problems by simply not using what you call a 'composite control. While I understand that you want to encapsulate some functionality in the associated view model, you don't need to set the view model to the UserControl.DataContext internally.
What I mean by this is that you can have a view model for any or all of your UserControls, but they're data classes, not UI classes, so keep them out of the view code. If you use this method of adding DataTemplates into Resources, then you won't need to set any DataContext properties at all:
<DataTemplate DataType="{x:Type ViewModels:YourUserControlViewModel}">
<Views:YourUserControl />
</DataTemplate>
The final difference is that you should add your view model for your UserControls as properties in a parent view model. This way, you still have no duplicated code (except maybe just a property declaration) and more importantly, you have no Binding problems from mixing DataContext values.
UPDATE >>>
When using this DataTemplate method of hooking up views and view models, you can display your view by Binding your view model property to the Content property of a ContentControl like this:
<ContentControl Content="{Binding YourViewModelProperty}" />
At run time, this ContentControl will be rendered as whatever view or UserControl that you defined in the DataTemplate of the relevant type for that property. Note that you shouldn't set the x:Key of the DataTemplate, otherwise you'd also need to set the ContentControl.ContentTemplate property and that can limit the possibilities afforded by this method.
For example, without setting the x:Key property on your DataTemplates, you could have a property of a base type and by setting it to different sub class, you can have different views for each from the one ContentControl. That is the basis of all of my views... I have one property of a base class view model data bound like this example and to change views, I just change the property to a new view model that is derived from the base class.
UPDATE 2 >>>
Here's the thing... you shouldn't have any 'proxy' object in your UserControls doing anything... it should all be done through properties. So just declare a DependencyProperty of the type of that object and supply it from the view model through data Binding. Doing it this way means that it will be easy to test the functionality of that class, whereas testing code behind views is not.
And finally, yes, it's perfectly fine doing this in MVVM:
<Controls:SomeUserControl DataContext="{Binding SomeViewModelProperty}" />
The overriding goal of MVVM is just to provide separation between the UI code and the view model code, so that we can easily test what's in the view models. That is why we try to remove as much functionality code from the views as possible.
within a usercontrol you should never set the datacontext to "this" or a new viewmodel. a developer/user of your MyUsercontrol expect that the datacontext inherit from top to bottom (from mainwindow to your myusercontrol).
your usercontrol xaml should use element binding
MyUserControl.xaml
<UserControl x:Name="uc">
<TextBlock Text="{Binding ElementName=uc, Path=Name}"/>
<TextBlock Text="{Binding ElementName=uc, Path=Value}"/>
this means your following code will work now in every situation
<Window xmlns:my="clr-namespace:MyNamespace.Controls">
<my:MyControl Name="{Binding Prop1}" Value="{Binding Prop2}" />
</Window>
the property Prop1 from Datacontext mainwindow is bound to the DP Name from your MyUsercontrol and the Textblock.Text within your MyUsercontrol is bound to the DP Name.
I've never met such a problem. It seems to be a little bit theoretical to me but maybe because of my approach to working with DataContext in WPF.
I minimize the explicit use DataContext property. I set it manually only for windows.
I have one dedicated method which is responsible for displaying new windows and it is the only one place where the DataContext property is set explicitly.
DataContext property for Windows is set to root ViewModel which contains child ViewModels, which contain...
I allow WPF to select which View should be used to display given a ViewModel by using DataTemplate
In my application I have a single ResourceDictionary which contains mappings between all ViewModels and Views.

Caliburn Micro design time using naming conventions

Using Caliburn Micro 1.5.1 I'm trying to get design time bindings to work in a WP8 app. I have created a design time ViewModel which I specify explicitly in the PhoneApplicationPage:
<phone:PhoneApplicationPage
d:DataContext="{Binding Source={d:DesignInstance Type=designTime:StartPageDesignTimeViewModel, IsDesignTimeCreatable=True}}"
micro:Bind.AtDesignTime="True"
The page is really no more than a RadDataBoundListBox from Telerik:
<Grid x:Name="ContentPanel">
<telerikPrimitives:RadDataBoundListBox x:Name="Rooms" ...>
As you can see, my ViewModel (and design time view model) have a public property named Rooms which I am binding to the ItemsSource collection using the named convention approach. The approach doesn't work at design time, however, unless I add the ItemsSource property
<Grid x:Name="ContentPanel">
<telerikPrimitives:RadDataBoundListBox x:Name="Rooms" ItemsSource="{Binding Rooms}" ...>
However, when I use ItemsSource binding I lose the CM wire-up magic like SelectedItem. Is there a way to get my bindings to work at design time using the naming conventions approach without modifying the page with anything other than design time attributes?
Ok, I figured it out. What I was looking for was the ability to overwrite existing bindings at all times. CM is more defensive than that, and so by default it won't replace existing bindings or values for an ItemsControl. This behavior is defined in ConventionManager.cs thusly:
AddElementConvention<ItemsControl>(ItemsControl.ItemsSourceProperty, "DataContext", "Loaded")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
if (!SetBindingWithoutBindingOrValueOverwrite(viewModelType, path, property, element, convention, ItemsControl.ItemsSourceProperty)) {
return false;
}
ApplyItemTemplate((ItemsControl)element, property);
return true;
};
What I did to force the framework to always replace the binding was to replace the call to SetBindingWithoutBindingOrValueOverwrite with a direct call to SetBinding in my BootStrapper. So:
ConventionManager.AddElementConvention<ItemsControl>(ItemsControl.ItemsSourceProperty, "DataContext", "Loaded")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
ConventionManager.SetBinding(viewModelType, path, property, element, convention, ItemsControl.ItemsSourceProperty);
ConventionManager.ApplyItemTemplate((ItemsControl) element, property);
return true;
};
(I also had to make this edit to the convention I had added earlier for RadDataBoundListBox)
I can see where someone might want to declaratively force replace an existing binding in some cases. Maybe I'll write a patch...

Property on static resource converter not bound

I have a value converter with a property I would like to bind to, but the binding never happens, i.e. the dependency property in my value converter always is null.
Background: I want to bind an enum to a combo box but have control over the text that is being displayed.
I implemented the value converter like this:
public class EnumDisplayer : DependencyObject, IValueConverter
{
public static readonly DependencyProperty LocalizerProperty =
DependencyProperty.Register(
"Localizer", typeof(ILocalizer), typeof(EnumDisplayer),
new PropertyMetadata(default(ILocalizer), OnLocalizerChanged));
public ILocalizer Localizer
{
get { return (ILocalizer) GetValue(LocalizerProperty); }
set { SetValue(LocalizerProperty, value); }
}
private static void OnLocalizerChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
// ...
}
//...
}
And I bind it like this:
<UserControl.Resources>
<Common:EnumDisplayer x:Key="companyTypes"
Localizer="{Binding CompanyTypeEnumLocalizer}" />
<!-- ... -->
</UserControl.Resources>
My class is an adapted version of the EnumDisplayer.
I fail to understand, why OnLocalizerChanged is never called. Can anyone provide some insight?
(Stack Team correct me if I am wrong)... ValueConverters do not automatically support in binding and there are reasons...
They arent really something that the WPF framework is actively aware of, given that they dont lie on visual or logical tree.
They are used as part of inner markup extensions. This is a merky area. Unless they implement marrkup extensions on their own, they would be bound to.
Although there are ways..
Straightforward way is to use MultiBinding instead of single binding. The second binding will replace your converter's need to host a dependncy property.
http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx
I hope this helps.
I think this may be because the ResourceDictionary in which you are creating the instance is not part of the visual tree, so it cannot find the DataContext and the Binding therefore always returns null.
You may be able to get around this by giving your UserControl an x:Name attribute and then binding using ElementName and DataContext.PropertyName:
<UserControl x:Name="Root">
<UserControl.Resouces>
<Common:EnumDisplayer x:Key="companyTypes"
Localizer="{Binding DataContext.CompanyTypeEnumLocalizer, ElementName=Root}" />
</UserControl.Resouces>
</UserControl>

WPF Databinding in XAML

I have little problem with databinding in my current project.
I have an ObservableCollection I want to bind to an ListBox.
public ObservableCollection<GeoDataContainer> geoList = new ObservableCollection<GeoDataContainer>();
...later...
geoListBox.ItemsSource = geoList;
This code works fine. The Listbox has a datatemplate and everything looks perfect.
But I don't want to use C# code for binding. I want to make the binding in the XAML Code.
I am searching for days but I don't get it. These are two lines C# code but to archive this in XAML it seems impossible without creating my own class for my collection or adding a DataProvider or resources or whatever.
Is there no easy way to do it?
All you have to do is expose the collection and bind to it. For example, if you expose it as:
public ICollection<GeoDataContainer> GeoList
{
get { return geoList; }
}
You will be able to bind to it as:
<ListBox ItemsSource="{Binding GeoList}"/>
The "trick" is to make sure that the DataContext of the ListBox is the class that exposes the GeoList property.
Another good way would be instantiating geoList as a resource
<WindowResources>
<l:GeoCollection x:Key="geoList"/>
</WindowResources>
Then you have
GeoCollection geoList = FindResource("geoList") as GeoCollection;
Of course, this is for cases when the data is related to the view only. If this is related to model or modelview, you use DataContext and bind to its properties.
Kent suggestion is the way to go...
On a further note, if you do not wish to set your DataContext to the list, you can also retrieve the property with an another form of binding:
Make sure your root control has a name, i.e. "Root"
{Binding ElementName=Root, Path=GeoList}

Categories

Resources