WPF CommandParameter is NULL first time CanExecute is called - wpf

I have run into an issue with WPF and Commands that are bound to a Button inside the DataTemplate of an ItemsControl. The scenario is quite straight forward. The ItemsControl is bound to a list of objects, and I want to be able to remove each object in the list by clicking a Button. The Button executes a Command, and the Command takes care of the deletion. The CommandParameter is bound to the Object I want to delete. That way I know what the user clicked. A user should only be able to delete their "own" objects - so I need to do some checks in the "CanExecute" call of the Command to verify that the user has the right permissions.
The problem is that the parameter passed to CanExecute is NULL the first time it's called - so I can't run the logic to enable/disable the command. However, if I make it allways enabled, and then click the button to execute the command, the CommandParameter is passed in correctly. So that means that the binding against the CommandParameter is working.
The XAML for the ItemsControl and the DataTemplate looks like this:
<ItemsControl
x:Name="commentsList"
ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
Width="Auto" Height="Auto">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Content="Delete"
FontSize="10"
Command="{Binding Path=DataContext.DeleteCommentCommand, ElementName=commentsList}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So as you can see I have a list of Comments objects. I want the CommandParameter of the DeleteCommentCommand to be bound to the Command object.
So I guess my question is: have anyone experienced this problem before? CanExecute gets called on my Command, but the parameter is always NULL the first time - why is that?
Update: I was able to narrow the problem down a little. I added an empty Debug ValueConverter so that I could output a message when the CommandParameter is data bound. Turns out the problem is that the CanExecute method is executed before the CommandParameter is bound to the button. I have tried to set the CommandParameter before the Command (like suggested) - but it still doesn't work. Any tips on how to control it.
Update2: Is there any way to detect when the binding is "done", so that I can force re-evaluation of the command? Also - is it a problem that I have multiple Buttons (one for each item in the ItemsControl) that bind to the same instance of a Command-object?
Update3: I have uploaded a reproduction of the bug to my SkyDrive: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip

I was having this same issue while trying to bind to a command on my view model.
I changed it to use a relative source binding rather than referring to the element by name and that did the trick. Parameter binding didn't change.
Old Code:
Command="{Binding DataContext.MyCommand, ElementName=myWindow}"
New Code:
Command="{Binding DataContext.MyCommand, RelativeSource={RelativeSource AncestorType=Views:MyView}}"
Update: I just came across this issue without using ElementName, I'm binding to a command on my view model and my data context of the button is my view model. In this case I had to simply move the CommandParameter attribute before the Command attribute in the Button declaration (in XAML).
CommandParameter="{Binding Groups}"
Command="{Binding StartCommand}"

I have found that the order in which I set Command and CommandParameter makes a difference. Setting the Command property causes CanExecute to be called immediately, so you want CommandParameter to already be set at that point.
I have found that switching the order of the properties in the XAML can actually have an effect, though I'm not confident that it will solve your problem. It's worth a try, though.
You seem to be suggesting that the button never becomes enabled, which is surprising, since I would expect the CommandParameter to be set shortly after the Command property in your example. Does calling CommandManager.InvalidateRequerySuggested() cause the button to become enabled?

I stumbled upon a similar problem and solved it using my trusty TriggerConverter.
public class TriggerConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// First value is target value.
// All others are update triggers only.
if (values.Length < 1) return Binding.DoNothing;
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
This value converter takes any number of parameters and passes the first of them back as the converted value. When used in a MultiBinding in your case it looks like the following.
<ItemsControl
x:Name="commentsList"
ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
Width="Auto" Height="Auto">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Content="Delete"
FontSize="10"
CommandParameter="{Binding}">
<Button.Command>
<MultiBinding Converter="{StaticResource TriggerConverter}">
<Binding Path="DataContext.DeleteCommentCommand"
ElementName="commentsList" />
<Binding />
</MultiBinding>
</Button.Command>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You will have to add TriggerConverter as a resource somewhere for this to work. Now the Command property is set not before the value for the CommandParameter has become available. You could even bind to RelativeSource.Self and CommandParameter instead of . to achieve the same effect.

I've come up with another option to work around this issue that I wanted to share. Because the CanExecute method of the command gets executed before the CommandParameter property is set, I created a helper class with an attached property that forces the CanExecute method to be called again when the binding changes.
public static class ButtonHelper
{
public static DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached(
"CommandParameter",
typeof(object),
typeof(ButtonHelper),
new PropertyMetadata(CommandParameter_Changed));
private static void CommandParameter_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as ButtonBase;
if (target == null)
return;
target.CommandParameter = e.NewValue;
var temp = target.Command;
// Have to set it to null first or CanExecute won't be called.
target.Command = null;
target.Command = temp;
}
public static object GetCommandParameter(ButtonBase target)
{
return target.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(ButtonBase target, object value)
{
target.SetValue(CommandParameterProperty, value);
}
}
And then on the button you want to bind a command parameter to...
<Button
Content="Press Me"
Command="{Binding}"
helpers:ButtonHelper.CommandParameter="{Binding MyParameter}" />
I hope this perhaps helps someone else with the issue.

I'll add what worked for me for a DataGridTemplateColumn with a button.
Change the binding from:
CommandParameter="{Binding .}"
to
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"
Not sure why it works, but it did for me.

I recently came across the same problem (for me it was for the menu items in a context menu), nad while it may not be a suitable solution for every situation, I found a different (and a lot shorter!) way of solving this problem:
<MenuItem Header="Open file" Command="{Binding Tag.CommandOpenFile, IsAsync=True, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" CommandParameter="{Binding Name}" />
Ignoring the Tag-based workaround for the special case of context menu, the key here is to bind the CommandParameter regularly, but bind the Command with the additional IsAsync=True. This will delay the binding of the actual command (and therefore its CanExecute call) a bit, so the parameter will already be available. This means, though, that for a brief moment, the enabled-state might be wrong, but for my case, that was perfectly acceptable.

You may be able to use my CommandParameterBehavior that I posted to the Prism forums yesterday. It adds the missing behaviour where a change to the CommandParameter cause the Command to be re-queried.
There's some complexity here caused by my attempts to avoid the memory leak caused if you call PropertyDescriptor.AddValueChanged without later calling PropertyDescriptor.RemoveValueChanged. I try and fix that by unregistering the handler when the ekement is unloaded.
You'll probably need to remove the IDelegateCommand stuff unless you're using Prism (and want to make the same changes as me to the Prism library). Also note that we don't generally use RoutedCommands here (we use Prism's DelegateCommand<T> for pretty much everything) so please don't hold me responsible if my call to CommandManager.InvalidateRequerySuggested sets off some sort of quantum wavefuntion collapse cascade that destroys the known universe or anything.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
namespace Microsoft.Practices.Composite.Wpf.Commands
{
/// <summary>
/// This class provides an attached property that, when set to true, will cause changes to the element's CommandParameter to
/// trigger the CanExecute handler to be called on the Command.
/// </summary>
public static class CommandParameterBehavior
{
/// <summary>
/// Identifies the IsCommandRequeriedOnChange attached property
/// </summary>
/// <remarks>
/// When a control has the <see cref="IsCommandRequeriedOnChangeProperty" />
/// attached property set to true, then any change to it's
/// <see cref="System.Windows.Controls.Primitives.ButtonBase.CommandParameter" /> property will cause the state of
/// the command attached to it's <see cref="System.Windows.Controls.Primitives.ButtonBase.Command" /> property to
/// be reevaluated.
/// </remarks>
public static readonly DependencyProperty IsCommandRequeriedOnChangeProperty =
DependencyProperty.RegisterAttached("IsCommandRequeriedOnChange",
typeof(bool),
typeof(CommandParameterBehavior),
new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsCommandRequeriedOnChangeChanged)));
/// <summary>
/// Gets the value for the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
/// </summary>
/// <param name="target">The object to adapt.</param>
/// <returns>Whether the update on change behavior is enabled.</returns>
public static bool GetIsCommandRequeriedOnChange(DependencyObject target)
{
return (bool)target.GetValue(IsCommandRequeriedOnChangeProperty);
}
/// <summary>
/// Sets the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
/// </summary>
/// <param name="target">The object to adapt. This is typically a <see cref="System.Windows.Controls.Primitives.ButtonBase" />,
/// <see cref="System.Windows.Controls.MenuItem" /> or <see cref="System.Windows.Documents.Hyperlink" /></param>
/// <param name="value">Whether the update behaviour should be enabled.</param>
public static void SetIsCommandRequeriedOnChange(DependencyObject target, bool value)
{
target.SetValue(IsCommandRequeriedOnChangeProperty, value);
}
private static void OnIsCommandRequeriedOnChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is ICommandSource))
return;
if (!(d is FrameworkElement || d is FrameworkContentElement))
return;
if ((bool)e.NewValue)
{
HookCommandParameterChanged(d);
}
else
{
UnhookCommandParameterChanged(d);
}
UpdateCommandState(d);
}
private static PropertyDescriptor GetCommandParameterPropertyDescriptor(object source)
{
return TypeDescriptor.GetProperties(source.GetType())["CommandParameter"];
}
private static void HookCommandParameterChanged(object source)
{
var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
propertyDescriptor.AddValueChanged(source, OnCommandParameterChanged);
// N.B. Using PropertyDescriptor.AddValueChanged will cause "source" to never be garbage collected,
// so we need to hook the Unloaded event and call RemoveValueChanged there.
HookUnloaded(source);
}
private static void UnhookCommandParameterChanged(object source)
{
var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
propertyDescriptor.RemoveValueChanged(source, OnCommandParameterChanged);
UnhookUnloaded(source);
}
private static void HookUnloaded(object source)
{
var fe = source as FrameworkElement;
if (fe != null)
{
fe.Unloaded += OnUnloaded;
}
var fce = source as FrameworkContentElement;
if (fce != null)
{
fce.Unloaded += OnUnloaded;
}
}
private static void UnhookUnloaded(object source)
{
var fe = source as FrameworkElement;
if (fe != null)
{
fe.Unloaded -= OnUnloaded;
}
var fce = source as FrameworkContentElement;
if (fce != null)
{
fce.Unloaded -= OnUnloaded;
}
}
static void OnUnloaded(object sender, RoutedEventArgs e)
{
UnhookCommandParameterChanged(sender);
}
static void OnCommandParameterChanged(object sender, EventArgs ea)
{
UpdateCommandState(sender);
}
private static void UpdateCommandState(object target)
{
var commandSource = target as ICommandSource;
if (commandSource == null)
return;
var rc = commandSource.Command as RoutedCommand;
if (rc != null)
{
CommandManager.InvalidateRequerySuggested();
}
var dc = commandSource.Command as IDelegateCommand;
if (dc != null)
{
dc.RaiseCanExecuteChanged();
}
}
}
}

There's a relatively simple way to "fix" this problem with DelegateCommand, though it requires updating the DelegateCommand source and re-compiling the Microsoft.Practices.Composite.Presentation.dll.
1) Download the Prism 1.2 source code and open the CompositeApplicationLibrary_Desktop.sln. In here is a Composite.Presentation.Desktop project that contains the DelegateCommand source.
2) Under the public event EventHandler CanExecuteChanged, modify to read as follows:
public event EventHandler CanExecuteChanged
{
add
{
WeakEventHandlerManager.AddWeakReferenceHandler( ref _canExecuteChangedHandlers, value, 2 );
// add this line
CommandManager.RequerySuggested += value;
}
remove
{
WeakEventHandlerManager.RemoveWeakReferenceHandler( _canExecuteChangedHandlers, value );
// add this line
CommandManager.RequerySuggested -= value;
}
}
3) Under protected virtual void OnCanExecuteChanged(), modify it as follows:
protected virtual void OnCanExecuteChanged()
{
// add this line
CommandManager.InvalidateRequerySuggested();
WeakEventHandlerManager.CallWeakReferenceHandlers( this, _canExecuteChangedHandlers );
}
4) Recompile the solution, then navigate to either the Debug or Release folder where the compiled DLLs live. Copy the Microsoft.Practices.Composite.Presentation.dll and .pdb (if you wish) to where you references your external assemblies, and then recompile your application to pull the new versions.
After this, CanExecute should be fired every time the UI renders elements bound to the DelegateCommand in question.
Take care,
Joe
refereejoe at gmail

After reading some good answers to similar questions I changed in your example the DelegateCommand slightly to make it work. Instead of using:
public event EventHandler CanExecuteChanged;
I changed it to:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
I removed the following two methods because I was too lazy to fix them
public void RaiseCanExecuteChanged()
and
protected virtual void OnCanExecuteChanged()
And that's all... this seems to ensure that CanExecute will be called when the Binding changes and after the Execute method
It will not automatically trigger if the ViewModel is changed but as mentioned in this thread possible by calling the CommandManager.InvalidateRequerySuggested on the GUI thread
Application.Current?.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)CommandManager.InvalidateRequerySuggested);

In .NET 7.0 RC1 this has been fixed.
(At least in a sense...)
It should now automatically reevaluate CanExecute() whenever CommandParameter changes, including upon initialization.
Although that does not prevent the initial call to CanExecute() when CommandParameter is still null, many ICommand implementations should already be handling that and it does render obsolete the obscure and problematic XAML attribute ordering workaround / hack.
As intimated by #Daniel-Svensson in a GitHub comment:
the actual issue here is that ICommand.CanExecute is not reevaluated
when the value bound to CommandParameter changes. Doing so would
obviously be the correct behavior, since the command parameter is
passed to CanExecute, so everyone expects this behavior intuitively.
And that is what is being fixed.
According to #pchaurasia14, a Sr. Engineering Manager for WPF at Microsoft:
This has been fixed in RC1 release. You may try it out. ... I meant, .NET 7 RC1.
The GitHub tracking issue #316 in the dotnet/wpf project is listed as closed. The code change CommandParameter invalidates CanExecute #4217 has been included in .NET 7.0 RC1. It was merged on July 21, 2022 and is included in the list of commits (scroll way down) for the RC1 release.

I've logged this as a bug against WPF in .Net 4.0, as the problem still exists in Beta 2.
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=504976

Some of these answers are about binding to the DataContext to get the Command itself, but the question was about the CommandParameter being null when it shouldn't be. We also experienced this. On on a hunch, we found a very simple way to get this to work in our ViewModel. This is specifically for the CommandParameter null problem reported by the customer, with one line of code. Note the Dispatcher.BeginInvoke().
public DelegateCommand<objectToBePassed> CommandShowReport
{
get
{
// create the command, or pass what is already created.
var command = _commandShowReport ?? (_commandShowReport = new DelegateCommand<object>(OnCommandShowReport, OnCanCommandShowReport));
// For the item template, the OnCanCommand will first pass in null. This will tell the command to re-pass the command param to validate if it can execute.
Dispatcher.BeginInvoke((Action) delegate { command.RaiseCanExecuteChanged(); }, DispatcherPriority.DataBind);
return command;
}
}

not sure if this will work in a data template, but here is the binding syntax I use in a ListView Context menu to grab the current item as a command parameter:
CommandParameter=
"{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},
Path=PlacementTarget.SelectedItem,
Mode=TwoWay}"

Its a long shot. to debug this you can try:
- checking the PreviewCanExecute event.
- use snoop/wpf mole to peek inside and see what the commandparameter is.
HTH,

The commandManager.InvalidateRequerySuggested works for me as well. I believe the following link talks about similar problem, and M$ dev confirmed the limitation in the current version, and the commandManager.InvalidateRequerySuggested is the workaround. http://social.expression.microsoft.com/Forums/en-US/wpf/thread/c45d2272-e8ba-4219-bb41-1e5eaed08a1f/
What important is the timing of invoking the commandManager.InvalidateRequerySuggested. This should be invoked after the relevant value change is notified.

Beside Ed Ball's suggestion on setting CommandParameter prior to Command, make sure your CanExecute method has a parameter of object type.
private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
{
// Your goes heres
}
Hope it prevents someone spending the huge amount of time I did to figure out how to receive SelectedItems as CanExecute parameter

Related

Selecting Current MenuItem in wpf

How can I select the currentItem in a menuitem collection. Like one would do with a listbox. I tried wrapping the collection in a collectionViewSource, However that brought be no such luck.
Thanks in advance.
The MenuBase, which ContextMenu and Menu derive from, inherits ItemsControl, which does not include the concept of SelectedItem. That's something that ListBox adds.
You do, however, have the ItemsControl.ItemTemplate. Which is awesome.
One option would be to make your ItemTemplate a ToggleButton. This gives you a couple of things. Inherently, ToggleButtons can look like they're selected using their IsChecked property. Second, they have a Command property which you can bind to a command in your ViewModel.
So, if you have something along the lines of:
<Menu ItemsSource="{Binding ThingsToBindTo}">
<Menu.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.Resources>
<conv:BindingProxy x:Key="proxy" Data="{Binding}" />
</Grid.Resources>
<ToggleButton Content="{Binding NameOrLabel}" CommandParameter="{Binding}" Command="{Binding Path=DataContext.SelectThingCommand, RelativeSource={RelativeSource AncestorType=Menu}}" >
<ToggleButton.IsChecked>
<Binding Mode="OneWay" Path="DataContext.SelectedThing" RelativeSource={RelativeSource AncestorType=Menu}">
<Binding.Converter>
<conv:ComparisonConverter CompareTo="{Binding Source={StaticResource proxy}, Path=Data}" />
</Binding.Converter>
</Binding>
</ToggleButton.IsChecked>
</ToggleButton>
</Grid>
</DataTemplate>
</Menu.ItemTemplate>
</Menu>
So this is a little complicated.
As per normal, you're binding to a list of items. ThingsToBindTo should be whatever your list is. Then you start defining your template. NameOrLabel is whatever property you want to appear on your toggle button. The command parameter is binding to the data item that the template is wrapping around by using nothing more than "{Binding}". The command is actually on the DataContext of your Menu, which is why RelativeSource is used here.
What this is saying is you're going to pass a command the thing that was just clicked. Effectively, you're selecting the button you click. Then, your command just needs to set a SelectedThing property in your ViewModel equal to whatever Thing is passed to it. Hopefully you have implemented a class that implements ICommand to create your delegate commands. If you don't, there are a lot of articles out there on how to do it. If you don't know how, put a comment on this post and I'll add the source code to do it.
Then we have the "IsChecked" bad boy. We're actually doing a binding long-hand there. This is the more complicated piece, but it allows a DataTemplated item to actually bind to itself within a converter.
First, you need the proxy object, which is explained here:
http://tomlev2.wordpress.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
Very simple to implement. Once it is done, the BindingProxy resource within your grid will work, and can act as an anchor back to the item bound to by the DataTemplate. The linked article explains why.
Then, you need a converter that compares two objects to each other.
public class ComparisonConverter : DependencyObject, IValueConverter
{
public object CompareTo
{
get { return (object)GetValue(CompareToProperty); }
set { SetValue(CompareToProperty, value); }
}
public static readonly DependencyProperty CompareToProperty =
DependencyProperty.Register("CompareTo", typeof(object), typeof(ComparisonConverter), new UIPropertyMetadata(null));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (CompareTo != null)
{
return CompareTo.Equals(value);
}
else
{
return false;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
So now that binding will take the selected item from the DataContext of the menu, and compare it to whatever the ToggleButton is bound to. If the two objects match, the button appears clicked/selected. If they don't match, the button doesn't look selected.
So I do happen to have that BindingProxy and my converter in the same namespace. You don't necessarily have to do that. I just usually have a namespace for "Xaml Trick" classes that I have to program.
This is a lot to digest, and I'm happy to clarify anything.
One other thing...if you don't like the "ToggleButton" look, you can always style them to look completely different. The thing that having a ToggleButton buys you is the "IsChecked" property and the Command property. You can make the ContentTemplate look like anything you want, which gives you a lot of freedom in styling your menu.
If the ListBox has its ItemsSource set to a generic list of a complex entity, using ListBox.SelectedValue will get you the currently selected data.
For example:
public partial class NameListView : Window
{
/// <summary>
/// Constructor
/// </summary>
public NameListView()
{
List<string> names = new List<string>();
names.Add("John Doe");
names.Add("Jane Doe");
lbNameList.ItemsSource = names;
}
/// <summary>
/// Selection changed event handler for ListBox lbNameList
/// </summary>
void lbNameList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
string currentValue = lbNameList.SelectedValue.ToString();
MessageBox.Show("Currently selected value: " + currentValue);
}
}
}
If you have a property in your contextfile ( like Codebehind file or ViewModel ) that represents the currentSelectedItem then you can write the following in your xaml :
<ListView x:Name="MyList"
ItemsSource="MySource"
SelectedItem="{Binding Path=MyCurrentSelectedItem}" IsSynchronizedWithCurrentItem="True">
Codebehind / ViewModel
public MyType MyCurrentSelectedItem { get; set; }

How to replace target of binding (silverlight 4.0)

Problem description: In my Silverlight application (4.0), I have a TextBox control, which background is bound to some source property. I created a behavior for TextBox control. Inside my behavior, I want to take that binding, and "redirect" to other target (lets say, to the behavior itself). In other words, when the source property of background binding is changed, instead of updating property on TextBox control, I want to update some another target property. How to do that? I tried reflection, but it not allowed in SL on private fields...
Thanks in advance.
You can get the existing Binding using FrameworkElement.GetBindingExpression. Here's a sample:
FrameworkElement yourControl = null; // the code to get the control goes here
BindingExpression bindingExpression =
yourControl.GetBindingExpression(TextBox.Background);
Binding binding = bindingExpression.ParentBinding; // it's your binding
Then, create a new Binding object, setup its properties (change target if required) and use SetBinding to attach it.
UPDATE
Now about the binding source.
Note that Source property will be non-null only if you set this property explicitly.
Other options for the Binding source include:
specific element: used if Binding.ElementName property is set
templated control: used if Binding.RelativeSource is set to a RelativeSource with Mode=RelativeSourceMode.TemplatedParent
binding target control: used if Binding.RelativeSource is set to a RelativeSource with Mode=RelativeSourceMode.TemplatedParent
DataContext: if neither Source, nor the previous 3 options apply.
If you want to clone a Binding, you should check all these options.
However, if you just need the data item, you'd better use BindingExpression.DataItem property, which should return the actual data item that is the binding source.
I'm not sure why you would want to "redirect". Is it still ok if the text in the textbox changes? If you're trying to do binding to another element on the screen, you can use Element binding that would occur after the tb1 textbox loses focus:
<StackPanel>
<TextBox x:Name="tb1" />
<TextBox Text="{Binding ElementName=tb1, Source=Text}" />
</StackPanel>
In a behavior, you can us the TextChanged event and capture it there.
public class TextBoxBehavior : Behavior<TextBox>
{
/// <summary>
/// Called after the Behavior is attached to an AssociatedObject.
/// </summary>
/// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.TextChanged += new TextChangedEventHandler(AssociatedObject_TextChanged);
}
/// <summary>
/// Called after the Behavior is detached from an AssociatedObject.
/// </summary>
/// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.TextChanged -= new TextChangedEventHandler(AssociatedObject_TextChanged);
}
void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
{
if(!string.IsNullOrEmpty(this.AssociatedObject.Text))
{
string enteredValue = this.AssociatedObject.Text;
// do what you want with the entered value
}
// if you want to reset it.. this.AssociatedObject.Text = string.Empty;
}
}

Can a WCF Ria Services entity be edited while submitting?

I have a silverlight application that uses WCF RIA services.
I want to submit changes every time a property is changed.
However if a user tries to change a another property in the same entity before the submit is complete I get the following error:
"This entity is currently read-only. One of the following conditions exist: a custom method has been invoked, a submit operation is in progress, or edit operations are not supported for the entity Type"
Scenario:
User changes property A in Entity 1
Application catches change and submits WCF DataContext
Soon after user changes property B in Entity 1. However this property is read-only due to submit in progress.
Is it possible change the behaviour of the DataContext so that I can update an entity during the submit process?
PLEASE NOTE - I MIGHT BE WAYYYY OFF ON THIS RESPONSE:
Let me try to get what your saying:
If i'm correct, on the interface, values are being changed which are bound to some entity. This entity, is what you want to be updated in real time on the server. If this is the case, I would recommend this:
Let's say I have a text box, and as the user types the value in the text box, it updates the binding entity, and i want that entity to be updated on the server at the same time - define a behaviour to take the keyup method and trigger e.g. (AssociatedObject.GetBindingExpression(TextBox.TextProperty).UpdateSource();)
Also, in this behaviour, I would give the text box the ability to define a method to bind to for the OnKeyUp event allowing me, to say, once the user presses "Enter" then actually do the udpate on the server. In addition, i would create a loading screen/child window to say "saving" - that would then cause "blocking" to occur to prevent any further user intervention during the save. On the call back. I would close the window that said loading.
Now, like i said, i'm not sure if this is the answer your are looking for, but the theory behind the idea, especially the blocking only on enter or on a final change seems to be your best bet. An example of the behaviour for the text box is below:
Include your library: using CustomControlsUI.Extensions;
Define the class for the text box: public class TTextBoxKeyUpBehavior:Behavior<TextBox>
Define the method pointer for the ontextkeyup that you want to dynamically bind to: protected MethodInfo OnTextBoxKeyUp { get; set; }
Define the public string that names the OnTextKeyUpMethod to bind to: OnTextBoxKeyUpMethod
Define the TextboxKeyUp event in the behavior:
/// <summary>
/// Method impl. for the onkey up event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBoxKeyUp(object sender, KeyEventArgs e)
{
if (!object.ReferenceEquals(AssociatedObject.GetBindingExpression(TextBox.TextProperty), null))
{
AssociatedObject.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
if (!string.IsNullOrEmpty(OnTextBoxKeyUpMethod) && !object.ReferenceEquals(AssociatedObject,null) &&
!object.ReferenceEquals(AssociatedObject.DataContext,null))
{
try
{
//use reflection to try and find the method being pointed to.
if (object.ReferenceEquals(OnTextBoxKeyUp, null))
{
MethodInfo _m = null;
_m = AssociatedObject.DataContext.GetType().GetMethod(OnTextBoxKeyUpMethod, new Type[] { typeof(object), typeof(KeyEventArgs) });
if (!object.ReferenceEquals(_m, null))
//set the pointer to the on text box key up method
OnTextBoxKeyUp = _m;
}
OnTextBoxKeyUp.Invoke(AssociatedObject.DataContext, new object[] { sender, e });
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }
}
}
Override the On Attached and On Detached methods:
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.KeyUp += TextBoxKeyUp;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.KeyUp -= TextBoxKeyUp;
}
Usage:
Include the namespace where the behavior is stored: xmlns:ccui="clr-namespace:CustomControlsUI.Behaviors;assembly=CustomControlsUI"
Include the namespaces for System.Windows.Interactivity and Microsoft.Expression.Interactions:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Attach the OnKeyUpTo the desired method in the viewmodel:
<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="6,4,0,0"
Name="txtFirstName" VerticalAlignment="Top" Width="200" Text="{Binding FirstName, Mode=TwoWay}">
<i:Interaction.Behaviors>
<ccui:TTextBoxKeyUpBehavior OnTextBoxKeyUpMethod="OnSearchKeyUp" />
</i:Interaction.Behaviors>
</TextBox>
Implement the method and property in the view model that should implement INotifyPropertyChanged found in System.ComponentModel
public string FirstName
{
get
{
return __fFirstName;
}
set
{
__fFirstName = value;
//this is a custom extension on INotifyPropertyChanged
this.NotifyPropertyChanged("FirstName", PropertyChanged);
}
}
Finally define the key up method to notify the server of the change:
#region "Helper Method"
public void OnSearchKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && IsSearchStateValid==true)
{
OnFindCustomers(sender);
}
}
#endregion
Please Note: I could be WAYYYYYYYYYYY Off on this answer. But it's just based on what i think you're looking for....

Sharing DataContext to UserControl in a type safe way

I'm developing my first Silverlight 4 app and are struggling on how to to share my DataContext set on the top element (a Grid) in my MainPage.xaml into an underlying UserControl, in a type safe way. The DataContext is an instance of my ViewModel class and my thought is to be able to bind certain elements in the UserControl to properties of the ViewModel.
I am pretty sure the ViewModel object bubbles down to my UserControl but how can I in the UserControl asure that the DataContext is of type PatternCreatorViewModel?
Hope this was understandable!
This is (in my lonely opinion) one of the biggest limitations of the data binding model in Silverlight and WPF, namely, that there's no type safety anywhere in the process. As soon as you type {Binding...} you're working without a net. MS managed to take a wonderfully glorious strongly-typed language like C# and tied it to a completely non-type-safe data binding model, thereby all but wrecking a decade of Anders Hejlsberg's wonderful work on C#. You expect this sort of "looseness" when working with dynamic languages, but not when you're dealing with C#.
This limitation really becomes problematic when you're changing the ViewModel underlying your Views, because of course, there's no easy way to test your data bindings. Normally, when you've got code that you can't test, you can at least rely on the compiler to tell you if what you're asking the code to do doesn't make any sense. But because MS made data bindings non-type-safe, not only can you not test your changes, you can't even rely on the compiler to tell you when they don't make any sense. And, to add insult to injury, you can't even rely on running your application and seeing if you get any error messages: because bindings always fail silently. The best you can do is turn up the logging level and walk through tons of debug error messages. Uggh. Nasty as hell.
See my blog posting here, another question I asked here, and my answer here for more thoughts on the underlying issue.
I should note that I seem to be virtually alone in my opinion about this one, so perhaps there's something huge that I'm just missing. But I personally think you've hit the nail right on the head.
Pleasd see update below: the first proposed solution may cause threading-issues.
One possibility is creating a DependencyProperty of the required type, updating that during DataContextChanged and binding to that.
DefaultEditor.xaml.cs:
public partial class DefaultEditor : UserControl
{
public DefaultEditor()
{
this.DataContextChanged += OnDataContextChanged;
InitializeComponent();
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetValue(propertyNameProperty, this.DataContext as IPropertyProvider);
}
public static readonly DependencyProperty propertyNameProperty = DependencyProperty.Register(
nameof(PropertyProvider), typeof(IPropertyProvider), typeof(DefaultEditor), new PropertyMetadata(default(IPropertyProvider)));
public IPropertyProvider PropertyProvider
{
get { return (IPropertyProvider)GetValue(propertyNameProperty); }
}
}
Note: I reduced the standard Visual Studio pattern for the DepenendencyProperty, because I did not want a public setter.
Also, make sure to add the event handler before calling InitializeComponent().
DefaultEditor.xaml:
<UserControl x:Class="MyApp.DefaultEditor" x:Name="self">
<Grid DataContext="{Binding ElementName=self, Path=PropertyProvider}">
<StackPanel>
<TextBlock Text="{Binding Index}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</UserControl>
Once x:Name="self" is defined I have Intellisense for Path=PropertyProvider and the other bindings.
Note: Be sure not to set the entire control's DataContext (which would be recursive), use another (top-level) element like the Grid.
And, in case it wasn't obvious: In the example above IPropertyProvider is a custom type that must be replaced with the required type.
UPDATE:
While the above does work, it can invite code to access DefaultEditor.PropertyProvider from a wrong thread (other than the element's dispatcher's thread), which leads to an InvalidOperationException. This can be resolved by replacing the DependencyProperty with a simple property and implementing INotifyPropertyChanged.
Here's an updated code-behind, the .xaml remains the same.
DefaultEditor.xaml.cs
public partial class DefaultEditor : UserControl, INotifyPropertyChanged
{
public DefaultEditor()
{
this.DataContextChanged += OnDataContextChanged;
InitializeComponent();
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
PropertyProvider = this.DataContext as IPropertyProvider;
}
private IPropertyProvider _propertyProvider;
public IPropertyProvider PropertyProvider { get => _propertyProvider; private set => SetField(ref _propertyProvider, value); }
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
Note: The INotifyPropertyChanged implementation is a Visual Studio (Resharper?) code-snippet.
Using this code, DefaultEditor.PropertyProvider can be accessed from any thread.

WPF MVVM : Commands are easy. How to Connect View and ViewModel with RoutedEvent

Suppose I have a view implemented as a DataTempate inside a resource Dictionary.
And I have a corresponding ViewModel.
Binding Commands are easy. But what if my View contains a control such as a ListBox, and I need to Publish an application wide event (Using Prism's Event Aggreagtor) based on the Item being Changed on the List.
if ListBox supports a command I could just bind it to a command in the ViewModel and publish the event. But Listbox doesn't allow such an option.
How do I bridge this?
EDIT:
Many great answers.
Take a look at this link http://blogs.microsoft.co.il/blogs/tomershamam/archive/2009/04/14/wpf-commands-everywhere.aspx
Thanks
Ariel
Instead of trying to bind a command to when the item changes, I looked at the problem another way.
If you bind the selected item of the ListBox to a property in the ViewModel, then when that property is changed you can publish the event. That way the ViewModel remains the source of the event and it is triggered by the item changing, which is what you want.
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
...
public class ViewModel
{
public IEnumerable<Item> Items { get; set; }
private Item selectedItem;
public Item SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem == value)
return;
selectedItem = value;
// Publish event when the selected item changes
}
}
Extend the control to support ICommandSource and decide which action should trigger the command.
I did this with Combo Box and used OnSelectionChanged as the trigger for the command. First I will show in XAML how I bind the command to the extended Control ComboBox which I called CommandComboBox, then I will show the code for CommandComboBox that adds the support for the ICommandSource to ComboBox.
1) Using CommandComboBox in your XAML code:
In your XAML namespace declarations include
xmlns:custom="clr-namespace:WpfCommandControlsLibrary;assembly=WpfCommandControlsLibrary">
Use the CommandComboBox in place of ComboBox and bind the command to it like so: Note that in this example I have a defined a command called SetLanguageCommand im my ViewModel and I am passing the selected value for this ComboBox as the parameter to the command.
<custom:CommandComboBox
x:Name="ux_cbSelectLanguage"
ItemsSource="{Binding Path = ImagesAndCultures}"
ItemTemplate="{DynamicResource LanguageComboBoxTemplate}"
Command="{Binding Path=SetLanguageCommand, Mode=Default}"
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=SelectedValue, Mode=Default}"
IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Grid.Column="1" Margin="0,0,20,0" Style="{DynamicResource GlassyComboBox}" ScrollViewer.IsDeferredScrollingEnabled="True"
/>
2) The code for CommandComboBox
The code for the file CommandComboBox.cs is included below. I added this file to a Class Library called WpfCommandControlsLibrary and made it a separate project so I could easily add any extend commands to whatever solution needed to use them and so I could easily add additional WPF Controls and extend them to support the ICommandSource inteface.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfCommandControlsLibrary
{
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:WpfCommandControlsLibrary"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:WpfCommandControlsLibrary;assembly=WpfCommandControlsLibrary"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:CustomControl1/>
///
/// </summary>
public class CommandComboBox : ComboBox, ICommandSource
{
public CommandComboBox() : base()
{
}
#region Dependency Properties
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandComboBox),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
// Make CommandTarget a dependency property so it can use databinding.
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register(
"CommandTarget",
typeof(IInputElement),
typeof(CommandComboBox),
new PropertyMetadata((IInputElement)null));
public IInputElement CommandTarget
{
get
{
return (IInputElement)GetValue(CommandTargetProperty);
}
set
{
SetValue(CommandTargetProperty, value);
}
}
// Make CommandParameter a dependency property so it can use databinding.
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(CommandComboBox),
new PropertyMetadata((object)null));
public object CommandParameter
{
get
{
return (object)GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
#endregion
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandComboBox cb = (CommandComboBox)d;
cb.HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
}
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}
// If Command is defined, selecting a combo box item will invoke the command;
// Otherwise, combo box will behave normally.
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}
// Keep a copy of the handler so it doesn't get garbage collected.
private static EventHandler canExecuteChangedHandler;
}
}
One option is to extend the control in question and add support for the particular command you require. For example, I've modified ListView before to support the ItemActivated event and related command.
Well, nobody answered.
So I've gave up and moved the implementation of the View outside the Dictionary into a regular UserControl, I've injected him a reference to the ViewModel.
Now when the ListBox fire the Event it's calls the ViewModel and from there everything is possible again.
Ariel
A great solution to this type of problem comes from the usage of Attached Properties.
Marlon Grech has taken the usage of Attached Properties to the next level by creating Attached Command Behaviors. Using these it is possible to bind any Command existing in a ViewModel to any Event existing in the view.
This is something I use a lot to deal with similar issues with ListBoxes, where I want them to open, or edit or do some action on a double click.
In this example I'm using an older version of Attached Command Behaviors, but the effect is the same. I have a style that is used for ListBoxItems which I am explicitly keying to.
However, it would be easy enough to create a application or window wide style applying to all ListBoxItems that sets the commands at a much higher level. Then, whenever the event for the ListBoxItem attached to the CommandBehavior.Event property would fire, it instead fires off the attached Command.
<!-- acb is the namespace reference to the Attached Command Behaviors -->
<Style x:Key="Local_OpenListItemCommandStyle">
<Setter Property="acb:CommandBehavior.Event"
Value="MouseDoubleClick" />
<Setter Property="acb:CommandBehavior.Command"
Value="{Binding ElementName=uiMyListBorder, Path=DataContext.OpenListItemCommand}" />
<Setter Property="acb:CommandBehavior.CommandParameter"
Value="{Binding}" />
</Style>
<DataTemplate x:Key="MyView">
<Border x:Name="uiMyListBorder">
<ListBox ItemsSource="{Binding MyItems}"
ItemContainerStyle="{StaticResource local_OpenListItemCommandStyle}" />
</Border>
</DataTemplate>
I have been writing behaviors (attached properties) to do this, and there are still cases where I need them.
For the usual case however, simply binding an event to a command, you can do everything in Xaml if you have Blend SDK 4 installed. Note that you will have to add a reference to System.Windows.Interactivity.dll, and to redistribute this assembly.
Expression Blend SDK for .NET 4
Microsoft SDKs (for future reference)
This example is invoking an ICommand DragEnterCommand on the ViewModel when the DragEnter event of the Grid is fired:
<UserControl xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragEnter">
<i:InvokeCommandAction Command="{Binding DragEnterCommand}" CommandParameter="{Binding ...}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</UserControl>
Try using Prism 2.
It comes with great extensions to commanding and opens many new posibilites (like commands to being tied to visual tree).

Resources