Command does not execute on form initialize for radio button - c#

My form has 2 radio buttons. When you press either one of them it executes a command that sets a string variable with the relative value for radio button set to true - this also has a CommandParameter that sends the value of the string Content into the Exectue function.
This works fine when a human is pressing a radio button. Variables get set and all is good.
However, I have coded in the xaml for one of the radio buttons to be set to checked by default - and this does not cause the command to be executed on startup of the form for the very first time. Hence the string variable that I hold the appropriate value for the radio button that is checked, never gets set.
How do I get my string variable recieve the value on startup from the Execute(param) method?
Here is the xaml:
<StackPanel Grid.Row="4" Grid.Column="1" Margin="3" Orientation="Horizontal">
<RadioButton GroupName="LcType" Name="TsMapPane" HorizontalAlignment="Left" Checked="TsMapPane_Checked" IsChecked="True"
Command="{Binding Path=LcTypeCommand}" CommandParameter="{Binding ElementName=TsMapPaneTextBox, Path=Text}" >
<RadioButton.Content>
<TextBlock Name="TsMapPaneTextBox" Text="TS_MAP_PANE"/>
</RadioButton.Content>
</RadioButton>
<RadioButton GroupName="LcType" Margin="10 0 0 0" Name="TsGroup" HorizontalAlignment="Left" Checked="TsGroup_Checked"
Command="{Binding Path=LcTypeCommand}" CommandParameter="{Binding ElementName=TsGroupTextBox, Path=Text}">
<RadioButton.Content>
<TextBlock Name="TsGroupTextBox" Text="TS_GROUP"/>
</RadioButton.Content>
</RadioButton>
</StackPanel>
Here is the ViewModel:
public ICommand LcTypeCommand { get; set; }
public MyViewModel()
{
LcTypeCommand = new RelayCommand((param) => LcTypeExecute(param), () => true);
}
private void LcTypeExecute(object param)
{
LcTypeName = param.ToString();
}
public string LcTypeName
{
get => _lcTypeName;
set => SetField(ref _lcTypeName, value);
}

The command is called only when the user clicks on the button.
Changing the state of the RadioButton raises the Checked and Unchecked events. You can connect a command to the Checked event, but there is no guarantee that the IsChecked property will be changed after the listener is connected. Since both are specified in XAML.
In my opinion, the most correct would be to call the command in Code Behind after XAML initialization.
InitializeComponent();
if (TsMapPane.Command is ICommand command &&
command.CanExecute(TsMapPane.CommandParameter))
{
command.Execute(TsMapPane.CommandParameter);
}
P.S. You can add the following extension method to the Solution:
public static partial class WinHelper
{
public static void TryExecute(this ICommandSource commandSource)
{
if (commandSource.Command is not ICommand command)
return;
if (command is RoutedCommand routedCommand)
{
IInputElement? target = commandSource.CommandTarget ?? commandSource as IInputElement;
if (routedCommand.CanExecute(commandSource.CommandParameter, target))
{
routedCommand.Execute(commandSource.CommandParameter, target);
}
}
else
{
if (command.CanExecute(commandSource.CommandParameter))
{
command.Execute(commandSource.CommandParameter);
}
}
}
}
Then the code will be simplified to this:
InitializeComponent();
TsMapPane.TryExecute();
shows a null value for "TsMapPane.CommandParameter"
At the time of XAML initialization, if the DataContext is assigned by an external container, bindings to the DataContext will not yet work.
Therefore, you need to execute the command once in the Loaded event:
public SomeWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
TsMapPane.TryExecute();
}

Related

Enable Save button when textchange/selected item change in user control

<TextBox Grid.Row="1" Grid.Column="2" Width="50" Text="{Binding Size}"></TextBox>
<ComboBox Grid.Row="2" Grid.Column="1" ItemsSource="{Binding MyList, Mode=OneTime}"
SelectedValue ="{Binding ListSelectedItem, Mode=TwoWay}"></ComboBox>
<Button Grid.Row="3" Grid.Column="2" Content="Save" Command="{Binding SaveCommand}" IsEnabled="False"/>
ViewModel,
public ICommand SaveCommand { get; }
public ConfigurationViewModel()
{
SaveCommand = new RelayCommand(SaveCommandExecute);
}
public int Size
{
get
{
return _size;
}
set
{
_size = value;
OnPropertyChanged();
}
}
private void SaveCommandExecute()
{
// save logic
}
I can able to save the data entered in textbox and selected value in combo box. By default, Save button should be disabled and if any change in textbox / combobox then enable the Save button.
if user reverts back to old value in textbox / combobox then Save button should be disabled back.
In yours RelayCommand might be a second parameter of Func<object, bool> canExecute. Then you can add method for checking if value has changed.
private bool CanSaveCommandExecute(object parameter) => this.Size != defaultValue;
And in your constructor add name of that method in SaveCommand as second parameter. I hope this will help you.

PopUp binding not done correctly

I have a listview which on mouse enter to a particular column, i try to launch a popup in viewmodel class by setting isOpen to true in MyAction2() function which gets called on when user enters mouse on that column of listview.
I observe that when the mouse-enter to that column.It calls my function (MyAction2() function in ViewModel, see code written below) but even on setting the isopen variable to true in MyAction2(), The set-get method of binded isOpen not get called. Now i feel there is problem in binding. Which normally should be correct i feel some thing is missing but i dont know what.
My Xaml (containing teh opup and the column in ListView which on mouse enter calls an event called MyAction2() in ViewModel):
<Grid>
<StackPanel>
<Popup Margin="10,10,0,13" Name="Popup1" IsOpen="{Binding PopUpLaunched,Mode=TwoWay}" Placement="Top" PopupAnimation="Fade" StaysOpen="True" HorizontalAlignment="Left" VerticalAlignment="Top" Width="194" Height="200" MinWidth="500" MinHeight="500">
<StackPanel>
<Border Background="Red">
<TextBlock Name="McTextBlock" Background="LightBlue"> This is popup text </TextBlock>
</Border>
</StackPanel>
</Popup>
</StackPanel>
</Grid>
ViewModel.cs
private bool popUpLaunched;
public bool PopUpLaunched {
get {
return popUpLaunched;
} //Get set never gets called even after the popUpLaunched=true in the MyAction2() call
set {
popUpLaunched = value;
OnPropertyChanged("PopUpLaunched");
}
}
private void MyAction2(object param) //The function which gets called on mouse event but do not pop ups the popup
{
popUpLaunched = true;
}
Whats wrong and where is wrong ?
You should set the PopupLaunched property instead of setting the popUpLaunched field for the setter to get called and the PropertyChanged event to get raised:
private void MyAction2(object param)
{
PopUpLaunched = true;
}
In order to implement such a binding, you can make that property a Dependency property like this
public static readonly DependencyProperty PopUpLaunched = DependencyProperty.Register(
"popUpLaunched", typeof(bool), typeof(MainPage), new PropertyMetadata(null));
public bool popUpLaunched
{
get { return (bool)GetValue(PopUpLaunched); }
set { SetValue(PopUpLaunched, value); }
}
If you are not working on the MainPage, change that typeof(MainPage) argument respectively. And adjust getter and setter for your needs.

Validate a TextBox upon button press in WPF/MVVM

I have a TextBox and a Button in my view. I have an ICommand method, String serial number property, and a IsEnabled property in my view model.
When the user clicks the Button I'd like to validate the serial number in the TextBox with the InDatabase property. If the contents in the TextBox are invalid, I would like to raise an error on the TextBox. If the contents are valid in the TextBox I'd like to disable the Button and execute the command.
Here is the view:
<StackPanel Width="Auto" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Center">
<UniformGrid Rows="3" >
<TextBlock Text="This device appears to be uninitialized."/>
<UniformGrid Rows="1" Columns="2">
<Label>Serial Number:</Label>
<TextBox Text="{Binding IdentifiedSerialNumber, Mode=TwoWay, ValidatesOnDataErrors=True}"></TextBox>
</UniformGrid>
<Button Content="Identify" Command="{Binding IdentifyCommand}" IsEnabled="{Binding CanExecuteDeviceRestoration}"/>
</UniformGrid>
</StackPanel>
Here is the view-model:
public string IdentifiedSerialNumber
{
get
{
return this.identifiedSerialNumber;
}
set
{
this.identifiedSerialNumber = value;
}
}
public ICommand IdentifyCommand
{
get
{
return new RelayCommand(this.RelayRestoreControllerIdentity);
}
}
public bool CanExecuteDeviceRestoration
{
get
{
return canExecuteDeviceRestoration;
}
private set
{
this.canExecuteDeviceRestoration = value;
RaisePropertyChanged("CanExecuteDeviceRestoration");
}
}
public async void RelayRestoreControllerIdentity()
{
await Task.Run(
() =>
{
this.RestoreControllerIdentity();
});
}
public bool InDatebase
{
get
{
return DatabaseConnection.DeviceExists(this.IdentifiedSerialNumber);
}
}
My question is how do I bind the behavior such that when the user click the Button the TextBox is validated, and if it fails it displays an error with a message and if it passes the Button will be disabled and the command will execute.
You need to implement IDataErrorInfo.
This would add an indexer which returns a string.
If empty string is returned it means no error.
You can return an empty string until button is pressed(u could use a flag).
when button is pressed,Run the validation logic and appropriately change the flag and Raise PropertyChanged event for IdentifiedSerialNumber
You can learn how to implement IDataErrorInfo from here.
Also you need to Raise PropertyChanged event for IdentifiedSerialNumber.

Toggle Button Two Way Binding Not Working (Universal Windows Platform)

I am trying to bind the "IsChecked" property on the ToggleButton to "ModelView.IsEnabled".
"ModelView.IsEnabled" is always "false"
but somehow the ToggleButton can still show as "Checked".
Is there anything wrong with the binding?
XAML
...
<Page.Resources>
<ModelView:ModelView x:Key="ModelView"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ToggleButton IsChecked="{Binding Source={StaticResource ModelView}, Path=IsEnabled, Mode=TwoWay}">
<TextBlock >UWP Toggle Button</TextBlock>
</ToggleButton>
</Grid>
...
ModelView.cs
using...
namespace App2
{
class ModelView : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler CanExecuteChanged;
private bool _isEnabled;
public bool IsEnabled
{
get {
return _isEnabled;
}
set
{
_isEnabled = false;
OnPropertyChanged("IsEnabled");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
Try this, it worked to me:
1. Xaml code changes:
<Grid>
<Grid.DataContext>
<soHelpProject:MainViewModel/>
</Grid.DataContext>
<ToggleButton IsChecked="{Binding IsToggled, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<TextBlock >UWP Toggle Button</TextBlock>
</ToggleButton>
</Grid>
regards,
In your class ModelView, change IsEnabled from this:
public bool IsEnabled
{
get {
return _isEnabled;
}
set
{
_isEnabled = false;
OnPropertyChanged("IsEnabled");
}
}
to this:
public bool IsEnabled
{
get {
return _isEnabled;
}
set
{
_isEnabled = value;
OnPropertyChanged("IsEnabled");
}
}
EDIT: If i use _isEnabled = !value; as you suggested, it still works, with button and state now showing opposite values:
EDIT 2: Now, if you want to properly test your binding, then you could add an extra regular button and do this:
private void button1_Click(object sender, RoutedEventArgs e)
{
myModelView.IsEnabled = !myModelView.IsEnabled;
}
so you can watch your ToggleButton switch between true and false every time you click Test Button. Please note that Test Button is not bound to anything, it's just for testing purposes. See corresponding XAML at the bottom.
The problem is that the way you're doing it, "forcing" IsEnabled to be always false, you're actually sabotaging your own code...:O)
And finally, it is not clear from your code when/where you're assigning your DataContext. Please see below how to do it.
XAML:
<Page.DataContext>
<local:MyModelView/>
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ToggleButton x:Name="toggleButton1" Content="ToggleButton" IsChecked="{Binding IsEnabled, Mode=TwoWay}" HorizontalAlignment="Center"/>
<TextBlock x:Name="textBlock1" Text="{Binding IsEnabled}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="126,0,201,286" />
<Button x:Name="button1" Click="button1_Click" Margin="127,400,0,220" Content="Test Button" Height="35" />
</Grid>
Code-behind:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
myModelView = new MyModelView();
this.DataContext = myModelView;
}
I've run into the same problem, be it not with a ToggleButton, but with a TextBox, where I wanted to format the text the user had entered.
In your case you want to change the IsChecked property in your viewmodel and have it reflected in the User Interface straight away (so always be unchecked). The reason you want that is of absolutely no importance.
The problem is that with UWP the getter of your property gets called as you would expect when you click the ToggleButton. The normal action for the ToggleButton is to change from unchecked to checked (and vice versa) and that is what happens in your case. But then you expect that NotifyPropetyChanged signals the control in the UI. And that's where it goes wrong. The getter never gets called when the setter is executed (including NotifyPropertyChanged), so the UI doesn't reflect what you did in your setter.
This is very different from what the TwoWay Binding used to do (and still does in WPF). So there is nothing wrong with your code, but it seems that the binding mechanism has changed, although Microsoft claims it didn't. If you would use x:Bind, it works fine, so hat might solve your problem.
To clarify things more I have taken your example and modified it slightly, to show the problem.
I've put a ToggleButton on the page with a TwoWay binding to a viewmodel, exactly as you did. Clicking on the ToggleButton will switch its state from checked to unchecked and vice versa, even though the setter in my viewmodel Always sets the property to false (so unchecked).
But I've also added a normal button, that I've bound to a command that also modifies the property that the ToggleButton is bound to. Clicking this button calls the setter on the property the ToggleButton is bound to. Of course the setter gets called just the same, but after that the binding to the ToggleButton gets called, so NotifyPropertyChanged in this case does cause a UI update.
If you use the debugger, you can see exactly what i mean.
So your problem can be solved by using x:Bind, or by figuring out another way to update the UI, which you shouldn't have to do if Binding was still working as it used to. Maybe Microsoft has implemented some kind of optimization that now destroys classic Binding.
No special things, just a MainPage and a viewmodel.
My code for MainPage.xaml
<Page x:Class="App10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:App10"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:ViewModel x:Key="viewModel" />
</Page.Resources>
<Grid x:Name="mainGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="10,20,10,0">
<Button
x:Name="Button"
Content="UWP Normal button"
Command="{Binding Source={StaticResource viewModel}, Path=SwitchIschecked}"
HorizontalAlignment="Stretch" />
<ToggleButton
x:Name="toggleButton"
Margin="0,10,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
IsChecked="{Binding Source={StaticResource viewModel}, Path=IsChecked,
Mode=TwoWay}">
<TextBlock>UWP Toggle Button</TextBlock>
</ToggleButton>
</StackPanel>
</Grid>
</Page>
The code for MainPage.xaml.cs
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App10
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
}
}
And the code for ViewModel.cs
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace App10
{
public class ViewModel : INotifyPropertyChanged
{
private bool _isChecked;
// property for TwoWay binding with ToggleButton
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
// extra var just to check 'value'
var _value = value;
// now always set it to false
_isChecked = false;
// Try to pass value of _isChecked to user interface
// because there is no check whether the value really
// has changed
// But this only works if the setter is not being called
// directly from the control the property is bound to
OnPropertyChanged();
}
}
private ICommand _switchChecked;
// ICommand for normal button, binding to Command
// calls method to set Property for ToggleButton
public ICommand SwitchIschecked
{
get
{
if ( _switchChecked == null )
_switchChecked = new ChangeChecked( new Action( ChangeVar ));
return _switchChecked;
}
set
{
_switchChecked = value;
}
}
// This will set the property for the ToggleButton
private void ChangeVar()
{
IsChecked = !IsChecked;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( [CallerMemberName] string propertyName = null )
{
var handler = PropertyChanged;
handler?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
}
}
/// <summary>
/// Quick class to implement ICommand
/// </summary>
class ChangeChecked : ICommand
{
Action _execute;
public ChangeChecked( Action execute )
{
_execute = execute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute( object parameter )
{
return true;
}
public void Execute( object parameter )
{
_execute();
}
}
}
IsEnabled property is indicating whether the user can interact with the control. IsPressed is readonly property. So IsChecked is probably what you need.

opening the appbar in metro style apps using binding property

My main page has the appbar and it is shared across different pages. I wrote the following code to open the appbar on the click of a gridview item.
XAML
<AppBar Opened="AppBar_Opened" IsOpen="{Binding IsAppBarOpen}">
Back end
private void Clock_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
App.ViewModel.SelectedClock = (Clock)ThemeGridView.SelectedItem;
App.WorldViewModel.IsAppBarOpen = true;
}
private void ThemeGridView_ItemClick(object sender, ItemClickEventArgs e)
{
App.ViewModel.SelectedClock = (Clock)ThemeGridView.SelectedItem;
App.WorldViewModel.IsAppBarOpen = true;
}
WorldViewModel
private bool _IsAppBarOpen;
public bool IsAppBarOpen
{
get { return _IsAppBarOpen; }
set { base.SetProperty(ref _IsAppBarOpen, value); }
}
GridView XAML
<GridView
Grid.Row="1"
Grid.Column="1"
x:Name="ThemeGridView"
ItemsSource="{Binding Clocks}"
ItemTemplate="{StaticResource WorldClockTemplate}"
SelectionChanged="Clock_SelectionChanged"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ThemeGridView_ItemClick"
>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
But the appbar is not popping up when i select the gridview item. There is no binding error so its really mysterious!
There is not way to bind IsOpen property according the msdn:
Note Binding to the IsOpen property doesn't have the expected results
because the PropertyChanged notification doesn't occur when the
property is set.
<AppBar Opened="AppBar_Opened" IsOpen="{Binding IsAppBarOpen, **Mode=TwoWay**}">
This works for me. I use MVVM Light Toolkit.
public bool AppBarIsOpen
{
get { return this._appBarIsOpen; }
set
{
if (this._appBarIsOpen == value) { return; }
this._appBarIsOpen = value;
this.RaisePropertyChanged("AppBarIsOpen"); // without INotifyPropertyChanged it doesn't work
}
}
<AppBar
IsSticky="True"
IsOpen="{Binding Path=AppBarIsOpen, Mode=TwoWay}">
Roman Weisert's answer correctly states the likely reason for it not working, although you also must make the binding two-way as Zack Weiner suggested (I'm not sure the reason for the latter since the binding is not working in the target-to-source direction anyway). The current value of AppBar.IsOpen may not be reflected by IsAppBarOpen of your view-model. When that's the case, and you try updating the value, it's possible that no PropertyChanged event is raised since you may not actually be updating a value. Instead, you may be just setting the value from false to false or from true to true. Most SetProperty method implementations do not raise the PropertyChanged event unless there is an actual change, and I presume yours is the same.
To fix the problem, consider modifying your view-model as follows:
public bool IsAppBarOpen
{
get { return _IsAppBarOpen; } //changes initiated from UI not reflected
set //not updated from UI
{
_IsAppBarOpen = value;
base.OnPropertyChanged();
}
}
bool _IsAppBarOpen;
The notable difference from your view-model's code, is that SetProperty is not called here so PropertyChanged is raised even when the backing store equals the newly introduced value. In case your base class differs, note that mine has an OnPropertyChanged method with the signature
void OnPropertyChanged( [CallerMemberName] string propertyName = null )
that serves to raise the PropertyChanged event.
I can see from your use of the code-behind, though, that you are not really following MVVM. If MVVM is not a concern to you, then you could forgo the IsAppBarOpen property altogether and just directly set AppBar.IsOpen. As someone who religiously adheres to MVVM, however, I do not recommend that you further head in that (sinful) direction.
I had the same issue and using Caliburn Micro for WinRT and with this code worked for me:
<AppBar IsOpen="{Binding AppBarsOpen}" Name="MainAppBar" Padding="10,0,10,0" AutomationProperties.Name="Bottom App Bar">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="LeftPanel" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
<Button Name="ShowFlyout" Style="{StaticResource BookmarksAppBarButtonStyle}" />
</StackPanel>
<StackPanel x:Name="RightPanel" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
<Button Style="{StaticResource SaveAppBarButtonStyle}" />
</StackPanel>
</Grid>
</AppBar>
And that's your property in ViewModel:
public bool AppBarsOpen
{
get { return _appBarsOpen; }
set
{
if (value.Equals(_appBarsOpen)) return;
_appBarsOpen = value;
NotifyOfPropertyChange(() => AppBarsOpen);
}
}
Had the same issue, solved it by adding the Closed event and updating the ViewModel from the code behind. Saw no other way since TwoWay binding was not working as Roman pointed out.
XAML
<AppBar x:Name="BottomAppBar1"
AutomationProperties.Name="Bottom App Bar"
Closed="BottomAppBar1_Closed"
IsOpen="{Binding IsOpen, Mode=TwoWay}"
IsSticky="True">
C# Code behind
private void BottomAppBar1_Closed(object sender, object e)
{
MainViewModel vm = this.DataContext as MainViewModel;
vm.IsOpen = false;
}
C# MainViewModel
public const string IsOpenPropertyName = "IsOpen";
private bool isOpen = false;
/// <summary>
/// Sets and gets the IsOpen property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public bool IsOpen
{
get
{
return isOpen;
}
set
{
RaisePropertyChanging(IsOpenPropertyName);
isOpen = value;
RaisePropertyChanged(IsOpenPropertyName);
}
}
You should bind both IsOpen and IsSticky two way because otherwise you will get problems with for example having to tap two time to unselect an item (once to close the app bar and once for unselecting) and also it's the will help having your app bar behave more standarly (will prevent the app bar to pop down on tap when an item is selected).
To show the app bar you will need to do the following (the order is important):
this.IsAppBarSticky = true;
this.IsAppBarOpen = true;
and to hide it, do the following:
this.IsAppBarSticky = false;
this.IsAppBarOpen = false;
Another way to make this work without having to use a codebehind handler for app bar closed event:
public class AppBarClosedCommand
{
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand),
typeof(AppBarClosedCommand), new PropertyMetadata(null, CommandPropertyChanged));
public static void SetCommand(DependencyObject attached, ICommand value)
{
attached.SetValue(CommandProperty, value);
}
public static ICommand GetCommand(DependencyObject attached)
{
return (ICommand)attached.GetValue(CommandProperty);
}
private static void CommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Attach click handler
(d as AppBar).Closed += AppBar_onClose;
}
private static void AppBar_onClose(object sender, object e)
{
// Get GridView
var appBar = (sender as AppBar);
// Get command
ICommand command = GetCommand(appBar);
// Execute command
command.Execute(e);
}
}
then in the XAML you can use it like :
common:AppBarClosedCommand.Command="{Binding AppBarClosedCommand}"
with the command function looking like:
public void OnAppBarClosed()
{
AppBarOpen = false;
}

Categories