I am not sure if this is an MVVM-Light bug or just something that doesn't work in WPF.... I have a button where I am setting the Command property to a RelayCommand. Everything works fine as long as I don't set the CommandParameter property. Once I do, the CanExecute callback quits working.
I am using the GalaSoft.MvvmLight.CommandWpf namespace as I am working in .Net 4.5.2. Here is a code snippit:
public RelayCommand<IList> SetFlagCommand { get; private set; }
...
SetFlagCommand = new RelayCommand<IList>(SetFlag, CanSetFlag);
...
mButtons.Add(new Button
{
...
Command = SetFlagCommand,
CommandParameter = new Binding("SelectedItems") { ElementName = "lstAllChoices" },
});
...
private void SetFlag(IList list)...
private bool CanSetFlag(IList list)...
The CanSetFlag method is called once, but then never again. If I don't set the CommandParameter property, it works as expected. Any ideas what is going on?
Thanks for any help!
You are not supposed to set the CommandParameter property to a Binding. Bind it using the BindingOperations.SetBinding method instead:
Button button = new Button()
{
Command = SetFlagCommand
};
BindingOperations.SetBinding(button, Button.CommandParameterProperty, new Binding("SelectedItems") { ElementName = "lstAllChoices" });
mButtons.Add(btn);
Also make sure that the type of the source property (SelectedItems) matches the type parameter T of the RelayCommand<T>.
Related
I added property in View:
[Reactive] public Point PositionLeftClick { get; set; } = new Point();
On mouse click I set property value.
And try use it as parameter for command parameter
this.WhenActivated(disposable =>
{
var positionLeftClickObservable = this.WhenAnyValue(x => x.PositionLeftClick);
this.BindCommand(this.ViewModel, x => x.CommandAddNodeWithUndoRedo, x => x.ItemAddNode,
positionLeftClickObservable).DisposeWith(disposable);
});
But parameter value in command always 0,0
How I can fix it?
Generally, I wouldn't put a [Reactive] property in a View. Normally I would delegate that to some ViewModel and bind it to the View.
ReactiveUI is an MVVM framework, and it works better when you provide a ViewModel for binding state to the View.
I created a new WPF MVVM application via Online Templates->WPF in VS2010->WPF MVVM project template. I created a checkbox labeled "Refresh Enabled?" next to the "Refresh" button that I wanted to enable/disable the "Refresh" button when clicked. I bound the IsChecked property of my checkbox to aMainWindowViewModel property I called CanRefreshDate, and it raises RaisePropertyChanged(()=>CanRefreshDate); in its setter. Also in the MainWindowViewModel, I added my newly created CanExecuteRefreshDate(), which returns the bool of CanRefreshDate property. However, when I click the checkbox, the button "Refresh" is never enabled/disabled to match. What is the proper way to fix this, and is this an oversight in the template or what?
Here's my modifications to the template code:
Xaml:
<CheckBox Content="Refresh Enabled?"
IsChecked="{Binding CanRefreshDate}"/>
MainWindowViewModel.cs:
private bool _CanRefreshDate;
public bool CanRefreshDate
{
get { return _CanRefreshDate; }
set
{
if (_CanRefreshDate != value)
{
_CanRefreshDate = value;
RaisePropertyChanged(() => CanRefreshDate);
}
}
}
public ICommand RefreshDateCommand { get { return new DelegateCommand(OnRefreshDate, CanExecuteRefreshDate); } }
private bool CanExecuteRefreshDate()
{
return CanRefreshDate;
}
I noticed that the template had RaiseCanExecuteChanged() misspelled RasieCanExecuteChanged() in DelegateCommand.cs and changed that. I was able to get it all working by removing RaiseCanExecuteChanged() and modifying the
public event Handler CanExecuteChanged;
to :
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
However, I would like to know what the proper solution for this is and why the template doesn`t work. Am i missing something, doing something wrong or what? Please create a new solution and use the template I did and tell me what is going on! Thanks!
The author fixed the issue and released version 4.1 of the template yesterday.
In Silverlight5 how to reference a Thing class from XAML:
xmlns:UserControls="clr-namespace:xyz.ClientApp.UserControls"
public class Thing : ContextMenu, IDisposable
{
public void Dispose()
{
MethodInfo infos = typeof(ContextMenu).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(a => a.Name.Equals("HandleRootVisualMouseMove")).FirstOrDefault();
Delegate handler = Delegate.CreateDelegate(typeof(MouseEventHandler), this, infos);
EventInfo info = System.Windows.Application.Current.RootVisual.GetType().GetEvent("MouseMove");
info.RemoveEventHandler(System.Windows.Application.Current.RootVisual, handler);
}
}
Am trying to fix a bug in ContextMenuService here
I think you are confusing attached properties and object instantiation syntax. ContextMenu is attached property of ContextMunueService and can not be accessed through your Thing class.
I havent tested it, but following code should work:
<controlsInputToolkit:ContextMenuService.ContextMenu>
<UserControls:Thing>
<!-- menu items here -->
</UserControls:Thing>
</controlsInputToolkit:ContextMenuService.ContextMenu>
Just wondering if this is a good practice or if it could cause any troubles in the long run. To be honest, I'm surprised it even works - it does the job, but I'm not sure if it's risky.
Basically we created a NumericTextBox that derives from TextBox, and we overrode the Text property with the new keyword to remove commas from the text:
public class NumericTextBox : TextBox
{
public new string Text
{
get
{
return base.Text.Replace(",", String.Empty);
}
set
{
base.Text = value;
}
}
}
What I don't like about it is that I know Text is a dependency property and we're overriding it, but surprisingly we can still bind to it in XAML:
<this:NumericTextBox x:Name="textBox"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=SomeText, Converter={StaticResource debugConverter}}" />
Then in C# when we call textBox.Text we do get the values without commas.
What do you guys think?
Perhaps you should add your class as an owner of the dependency property and override the getter and setter there:
public class NumericTextBox : TextBox
{
public NumericTextBox() { }
public static readonly DependencyProperty NumericTextProperty = TextBox.TextProperty.AddOwner(typeof(NumericTextBox), new PropertyMetadata(null));
public new string Text
{
get { return ((string)this.GetValue(NumericTextProperty )).Replace(",", String.Empty); }
set { this.SetValue(NumericTextProperty , value); }
}
}
You also have the possibility of overriding the metadata of the dependency property to hook in a custom validation callback method.
You approach doesn't work, because WPF doesn't actually use the class properties to change the value, but the dependency property system. It simply calls the SetValue method as you do in your property setter. You can try it out by setting a breakpoint in the setter, and changing the bound property in the gui. The setter breakpoint will never be hit. But you can hook into the events provided by the dependency property metadata.
I have an INotifyProperty Screen item that I have bound to a wpf control.
Ok... I Simplified everything and am posting more code. I have a MainViewModel with the selected screen property.
public Screen SelectedScreen
{
get { return this.selectedScreen; }
set
{
this.selectedScreen = value;
this.OnPropertyChanged("SelectedScreen");
}
}
I have a textbox that is bound to this property:
<TextBlock Text="{Binding Path=SelectedScreen.ScreenNumber}" />
This all works initially. I have created another control that is changing the selected screen with the following code.
public Screen SelectedScreen
{
get { return (Screen)GetValue(SelectedScreenProperty); }
set
{
this.SetValue(SelectedScreenProperty, value);
for (int x = 0; x < this.Screens.Count; ++x)
this.Screens[x].IsSelected = false;
value.IsSelected = true;
}
}
public ObservableCollection<Screen> Screens
{
get { return (ObservableCollection<Screen>)GetValue(ScreensProperty); }
set { this.SetValue(ScreensProperty, value); }
}
public static readonly DependencyProperty SelectedScreenProperty =
DependencyProperty.Register("SelectedScreen",
typeof(Screen),
typeof(ScreenSelection));
public static readonly DependencyProperty ScreensProperty =
DependencyProperty.Register("Screens",
typeof(ObservableCollection<Screen>),
typeof(ScreenSelection),
new UIPropertyMetadata(new ObservableCollection<Screen>()));
This screen selection control is working. When I change screens and put a breakpoint on the set property of SelectedScreen it is called which then calls the SelectedScreen property of the MainViewModel. So the event is firing, but the textbox isn't updated even though it binds correctly the first time.
Does the class which contains the SelectedScreen property implement INotifyPropertyChanged? When the SelectedScreen property changes, the containing class should raise the PropertyChanged event, and typically, WPF should update the Binding.
Thank you gehho for looking at this. I figured it out and there is no way you had enough information to be able too. I was inheriting from ViewModelBase in the MainViewModel that was inheriting from ObservableObject where I implemented INotifyPropertyChanged. The problem is that I implemented the methods for INotifyPropertyChanged in both classes and WPF was listening to the wrong one. Very obscure. Very annoying. Very lasjkdf;ashdoh