I have this App.xaml.cs code in my WPF project:
public partial class App : Application
{
public static bool IsInitialized
{
get;
private set;
}
public static async Task Initialize()
{
// Mark application as initialized
IsInitialized = true;
}
}
Main window of my application should be disabled (IsEnabled== False) while App.IsInitialized flag is not set, so window gets enabled when Initialize() finished.
How to achieve this?
Tried to use this XAML:
IsEnabled="{Binding App.IsInitialized, Mode=TwoWay}"
You may use:
IsEnabled="{Binding Source={x:Static Application.Current}, Path=Initialized}"
And also you should notify when the property Initialized gets updated in order to get the UI updated as well, for this you should implemented the INotifyPropertyChanged interface and raise the PropertyChange event on your Initialize() method.
Hop this helps.
Taken (and modified) from MS example in the documentation:
<Binding Source="{x:Static Application.Current}" Path="Initialized"/>
Yes, static is incorrect in most of cases, so i gonna implement INotifyPropertyChanged so UI will receive update notifications from my 'controller' class.
Also, this is brilliant code for future: https://gist.github.com/schuster-rainer/2644730
This is INotifyPropertyChanged implementation sample.
public class AppController : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool m_bInit;
private PropertyChangedEventArgs m_bInitEA = new PropertyChangedEventArgs("IsInitialized");
public bool IsInitialized
{
get { return m_bInit; }
set
{
m_bInit = value;
if (PropertyChanged != null)
PropertyChanged(this, m_bInitEA);
}
}
}
This is XAML:
<Window x:Class=".......
Loaded="OnLoaded" DataContext="{x:Static Application.Current}"
IsEnabled="{Binding Controller.IsInitialized}">
Related
I'm having some difficulty with Context Menu commands on my View Model.
I'm implementing the ICommand interface for each command within the View Model, then creating a ContextMenu within the resources of the View (MainWindow), and using a CommandReference from the MVVMToolkit to access the current DataContext (ViewModel) Commands.
When I debug the application, it appears that the CanExecute method on the command is not being called except at the creation of the window, therefore my Context MenuItems are not being enabled or disabled as I would have expected.
I've cooked up a simple sample (attached here) which is indicative of my actual application and summarised below. Any help would be greatly appreciated!
This is the ViewModel
namespace WpfCommandTest
{
public class MainWindowViewModel
{
private List<string> data = new List<string>{ "One", "Two", "Three" };
// This is to simplify this example - normally we would link to
// Domain Model properties
public List<string> TestData
{
get { return data; }
set { data = value; }
}
// Bound Property for listview
public string SelectedItem { get; set; }
// Command to execute
public ICommand DisplayValue { get; private set; }
public MainWindowViewModel()
{
DisplayValue = new DisplayValueCommand(this);
}
}
}
The DisplayValueCommand is such:
public class DisplayValueCommand : ICommand
{
private MainWindowViewModel viewModel;
public DisplayValueCommand(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (viewModel.SelectedItem != null)
{
return viewModel.SelectedItem.Length == 3;
}
else return false;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show(viewModel.SelectedItem);
}
#endregion
}
And finally, the view is defined in Xaml:
<Window x:Class="WpfCommandTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCommandTest"
xmlns:mvvmtk="clr-namespace:MVVMToolkit"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<mvvmtk:CommandReference x:Key="showMessageCommandReference" Command="{Binding DisplayValue}" />
<ContextMenu x:Key="listContextMenu">
<MenuItem Header="Show MessageBox" Command="{StaticResource showMessageCommandReference}"/>
</ContextMenu>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding TestData}" ContextMenu="{StaticResource listContextMenu}"
SelectedItem="{Binding SelectedItem}" />
</Grid>
</Window>
To complete Will's answer, here's a "standard" implementation of the CanExecuteChanged event :
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
(from Josh Smith's RelayCommand class)
By the way, you should probably consider using RelayCommand or DelegateCommand : you'll quickly get tired of creating new command classes for each and every command of you ViewModels...
You have to keep track of when the status of CanExecute has changed and fire the ICommand.CanExecuteChanged event.
Also, you might find that it doesn't always work, and in these cases a call to CommandManager.InvalidateRequerySuggested() is required to kick the command manager in the ass.
If you find that this takes too long, check out the answer to this question.
Thank you for the speedy replies. This approach does work if you are binding the commands to a standard Button in the Window (which has access to the View Model via its DataContext), for example; CanExecute is shown to be called quite frequently when using the CommandManager as you suggest on ICommand implementing classes or by using RelayCommand and DelegateCommand.
However, binding the same commands via a CommandReference in the ContextMenu
do not act in the same way.
In order for the same behaviour, I must also include the EventHandler from Josh Smith's RelayCommand, within CommandReference, but in doing so I must comment out some code from within the OnCommandChanged Method. I'm not entirely sure why it is there, perhaps it is preventing event memory leaks (at a guess!)?
public class CommandReference : Freezable, ICommand
{
public CommandReference()
{
// Blank
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference), new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (Command != null)
return Command.CanExecute(parameter);
return false;
}
public void Execute(object parameter)
{
Command.Execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandReference commandReference = d as CommandReference;
ICommand oldCommand = e.OldValue as ICommand;
ICommand newCommand = e.NewValue as ICommand;
//if (oldCommand != null)
//{
// oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;
//}
//if (newCommand != null)
//{
// newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;
//}
}
#endregion
#region Freezable
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
#endregion
}
However, binding the same commands via a CommandReference in the
ContextMenu do not act in the same way.
That's a bug in CommandReference implementation. It follows from these two points:
It is recommended that the implementers of ICommand.CanExecuteChanged hold only weak references to the handlers (see this answer).
Consumers of ICommand.CanExecuteChanged should expect (1) and hence should hold strong references to the handlers they register with ICommand.CanExecuteChanged
The common implementations of RelayCommand and DelegateCommand abide by (1). The CommandReference implementation doesn't abide by (2) when it subscribes to newCommand.CanExecuteChanged. So the handler object is collected and after that CommandReference no longer gets any notifications that it was counting on.
The fix is to hold a strong ref to the handler in CommandReference:
private EventHandler _commandCanExecuteChangedHandler;
public event EventHandler CanExecuteChanged;
...
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= commandReference._commandCanExecuteChangedHandler;
}
if (newCommand != null)
{
commandReference._commandCanExecuteChangedHandler = commandReference.Command_CanExecuteChanged;
newCommand.CanExecuteChanged += commandReference._commandCanExecuteChangedHandler;
}
...
private void Command_CanExecuteChanged(object sender, EventArgs e)
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, e);
}
In order for the same behaviour, I must also include the EventHandler
from Josh Smith's RelayCommand, within CommandReference, but in doing
so I must comment out some code from within the OnCommandChanged
Method. I'm not entirely sure why it is there, perhaps it is
preventing event memory leaks (at a guess!)?
Note that your approach of forwarding subscription to CommandManager.RequerySuggested also eliminates the bug (there's no more unreferenced handler to begin with), but it handicaps the CommandReference functionality. The command with which CommandReference is associated is free to raise CanExecuteChanged directly (instead of relying on CommandManager to issue a requery request), but this event would be swallowed and never reach the command source bound to the CommandReference. This should also answer your question as to why CommandReference is implemented by subscribing to newCommand.CanExecuteChanged.
UPDATE: submitted an issue on CodePlex
An easier solution for me, was to set the CommandTarget on the MenuItem.
<MenuItem Header="Cut" Command="Cut" CommandTarget="
{Binding Path=PlacementTarget,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}}"/>
More info: http://www.wpftutorial.net/RoutedCommandsInContextMenu.html
I have a small problem with my C# code and binding a property.
Here I have the following xaml:
<Image Source="{Binding downloaded, Source={StaticResource itemsViewSource}}" Width="20" Height="20" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Top"/>
And there is the code I'm trying to make working:
class Ressource : INotifyPropertyChanged
{
public String downloaded { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
Debug.WriteLine("Property changed.");
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
My problem is that the NotifyPropertyChanged function is called (the debug appears), the string content is changed but I don't see my image appear.
Does anyone have a solution to this.
Thanks!
EDIT:
After multiple useful answers but no change appearing even if the propertyChanged function is called,I'm starting to wonder if maybe changing the path of the image source is really possible.
Can the image be updated when the path is changed?
Here is the code after the changes suggested:
public class Ressource : INotifyPropertyChanged
{
public String downloaded
{
get
{
return _downloaded;
}
set
{
_downloaded = value;
if (PropertyChanged != null)
PropertyChanged(this,new PropertyChangedEventArgs("downloaded"));
}
}
You should change the property declaration so that view can be notified what source property is changed in View Model and update the control for notified property's value.
private String _downloaded;
public String downloaded
{
get
{
return _downloaded;
}
set
{
_downloaded = value;
NotifyPropertyChanged("downloaded");
}
}
The C# View Model Source Code is
class Ressource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private String _downloaded;
public string downloaded
{
get { return _downloaded; }
set
{
_downloaded= value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("downloaded"));
}
}
}
Add UpdateSourceTrigger=PropertyChanged to you binding.
You can only apply databinding when the accessibility level is public. The default accessibility level of a class is internal. You haven't applied an accessibility level, so your class Ressource is internal. Make it public and it should work.
public class Ressource : INotifyPropertyChanged
UPDATE 1:
If your image has been set to build action Resource you can try this string: "/AssemblyName;component/Assets/available.png".
OR for .Net Framework 4.5:
"pack://application:,,,/AssemblyName;component/Assets/available.png"
Replace AssemblyName with your assembly name (you can use Assembly.GetExecutingAssembly().GetName().Name to get your assembly name dynamically)
Okay so that was a rookie mistake but I prefere showing what was the problem since I found no topic explaining what could have been the problem.
However I found it myself so... I guess no one really needs it. Anyway:
I have not been clear enough.
In my example, I have the image source bound to the downloaded field in the Resource class.
The problem was that the resource objects were contained in another class which did not implement INotifyPropertyChanged.
Once I did, everything works fine.
Thanks to everyone one who tried to help me, sorry for the noobness and lack of clarity.
Code following if anyone struggles with this:
Part of Resource :
public class Ressource : INotifyPropertyChanged
{
private String _downloaded;
public String downloaded
{
get { return this._downloaded; }
set
{
this._downloaded = value;
raiseProperty("downloaded");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void raiseProperty(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
And the container :
class personalSeance : INotifyPropertyChanged
{
public ObservableCollection<Ressource> listRess { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void raiseOnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
And the simplest binding ever:
<Image Source="{Binding downloaded}" Width="20" Height="20" Margin="3" HorizontalAlignment="Right" VerticalAlignment="Top"/>
I'm sure this is a very basic question but I don't even know the technical term / jargon to Google and self-educate on.
I have created a simple model implementing INotifyPropertyChanged.
public class PushNotes : INotifyPropertyChanged
{
public string CompletePushNotes { get; set; }
}
Binding in cs:
evt_pushNotes = new PushNotes()
{
CompletePushNotes = "HelloThere"
};
this.DataContext = evt_pushNotes;
//snip later in code
Helpers.UpdateCompletePushNotes();
In XAML:
<xctk:RichTextBox x:Name="PushEmail" Text="{Binding Path=CompletePushNotes, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="40,398,40,40">
<xctk:RichTextBox.TextFormatter>
<xctk:PlainTextFormatter />
</xctk:RichTextBox.TextFormatter>
</xctk:RichTextBox>
Helper:
internal static class Helpers
{
internal static void UpdateCompletePushNotes()
{
//duhhhh what do I do now??
//If I create a new PushNotes it will be a different instantiation....???
}
}
Now this is all fine but I have a method in a helper class that needs to change the CompletePushNotes.
Again I know this is a simplistic / newbie question but I don't know what I need to learn.
So do I make my PushNotes class static, or singleton. Is there some global binding "tree" I can walk to find my instantiated and bound PushNotes class that is attached to the UI element?
Not looking for an a handout just need to know what it is I'm looking for.
TIA
Your PushNotes class does not implement the INotifyPropertyChanged interface. Once you have implemented it, you need to modify your CompletePushNotes property to have a backing field and in the setter of the property you can raise the PropertyChanged event to notify the UI of the source property update.
public class PushNotes : INotifyPropertyChanged
{
string completePushNotes;
public string CompletePushNotes
{
get
{
return completePushNotes;
}
set
{
completePushNotes = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Making the PushNotes class static will not help you. You seem to have a variable of some sort to the PushNotes instance (evt_pushNotes), so just do:
evt_pushNotes.CompletePushNotes = something;
If you have a helper class that does something, call the method in the helper class and get the value back or pass the PushNotes instance into the helper class as a parameter.
internal static class Helpers
{
internal static void UpdateCompletePushNotes(PushNotes pushNotes)
{
pushNotes.CompletePushNotes = something;
}
}
I am developing an application in WPF using MVVM, but I am stuck with the ICommand objects.
I have a windows which contains some buttons, so, I bind them to their respective ICommand in XAML as below:
<Button Command="{Binding DoSomethingCommand}" Content="Do Something" />
Then, In my view-model class I have written the following:
public class MyViewModel : ObservableObject
{
private bool isDoSomethingButtonEnabled = false;
....
public ICommand DoSomethingCommand
{
get;
private set;
}
....
....
public MyViewModel()
{
DoSomethingCommand = new DelegateCommand<String>(this.OnDoSomething, this.CanDoSomething);
}
private void OnDoSomething(String arg)
{
}
private bool CanDoSomething(String arg)
{
return isDoSomethingButtonEnabled;
}
....
}
So, Since I need that my button is not enabled the first time the window opens, I set my variable isDoSomethingButtonEnabled to false. And it works, the button is disabled at the beginning, but my problem is that when I change the variable isDoSomethingButtonEnabled to true at run time my button is still disabled.
I have even done some tests after changing the variable isDoSomethingButtonEnabled to true, printing the result of DoSomethingCommand.CanExecute() and it shows "true"!
so, what Should I do in order to enable my button??
Thank you in advance
There is an event called CanExecuteChanged on the ICommand interface which:
Occurs when changes occur that affect whether or not the command
should execute.
With the Prism DelegateCommand you can raise this event with the RaiseCanExecuteChanged method:
public void SomeMethod()
{
//do some work
isDoSomethingButtonEnabled = true;
DoSomethingCommand.RaiseCanExecuteChanged();
}
In my mvvm ViewModel I have such field
public int Delta { get; private set; }
However when I update it like that:
Delta = newValue;
UI is not refreshed.
I was thinking that databinding will do that for me. For example I can declare collection as ObservableCollection and then databinding will work.
However there are no ObservableInt, how to say View that it need to be refreshed then?
Probably I should raise some event "notify property changed" or something?
You have two choices:
Implement the INotifyPropertyChanged interface on your class.
Inherit from DependencyObject and implement Delta as a DependencyProperty.
The simplest option is #1. You can implement the INotifyPropertyChanged interface on your class quite easily:
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set { _delta = value; PropertyChanged?.Invoke(nameof(Delta)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
You can read more about using and implementing dependency properties on MSDN.
While we're at it with improving the answer, some of the other new additions of c# 6.0 and 7.0 help make it ever more compact:
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set { _value = value; NotifyPropertyChanged(nameof(Value)); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
This way, you aren't using any "embedded values" (i.e - the property's name) and are keeping the code refactor-safe.
And there's also no need for redundant code blocks due to c# 6.0 and 7.0's new Expression body features
Using #LBushKin's Answer, i modified it to
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value; }
set { _value = value; NotifyPropertyChanged("Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and to set it up:
class MainWindow ...
// a bool with initial value of true
public static Prop<bool> optionBool { get; set; } = new Prop<bool>{ Value = true };
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// connect UI to be able to use the Prop
DataContext = this;
}
and to use it:
<Grid ...
<CheckBox Content="Da Check" ... IsChecked="{Binding optionBool.Value}"/>
There is also a Collection and 2-Properties version here:
Utils.ObservableProperties.cs (this repo contains several related classes)
Just implement INotifyPropertyChanged Interface in your class and use it to raise a PropertyChanged for your Property and then UI will update. If you are using an MVVM project template then there is a good chance you already have a helper method implemented you only need to use it.
MSDN INotifyPropertyChanged
GalaSoft MVVM Light Toolkit
The ObservableCollection raises events automatically but for your own properties you have to raise the events yourself.
A good example is here: http://www.codeproject.com/Tips/228352/Naming-Properties-in-MVVM?display=Print
I'd suggest using mvvm light: http://mvvmlight.codeplex.com, I used it in silverlight and wpf applications. Very easy to use and provides a messageing system between model, view model and view.
Adding on to https://stackoverflow.com/a/8316100/5725669, there is a new and easy way to do this without remembering to keep track of PropertyChanged?.Invoke(nameof(Delta)); in every location
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set {
_delta = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public YourClass()
{
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
It makes use of CallerMemberName for skipping manual entries for property name. More details on this MSDN Doc