I am starting to play with Realm, and I am trying to bind a collection from the Realm database to a ListView. The binding works fine, but my ListView does not update when adding new items. My understanding is that IRealmCollection<> implements INotifyCollectionChanged and INotifyPropertyChanged events.
Here is a simple application to reproduce the issue:
View:
<Page x:Class="App3.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:App3"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Button Click="ButtonBase_OnClick" Content="Add" />
<ListView x:Name="ListView">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</Page>
CodeBehind:
namespace App3
{
public class Thing : RealmObject
{
public string Id { get; set; } = Guid.NewGuid().ToString();
}
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private Realm _realm;
private IRealmCollection<Thing> things;
public MainPage()
{
this.InitializeComponent();
_realm = Realm.GetInstance();
things = (IRealmCollection<Thing>)_realm.All<Thing>();
ListView.ItemsSource = things;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_realm.Write(() =>
{
var thing = new Thing();
_realm.Add(thing);
});
}
}
}
I normally use MVVM (Template10), but this is a simple application to demonstrate the issue. Clicking the Add button adds an item to the database, but the ListView only updates when the application is first loaded. I have read similar questions, but I have not been able to find an answer that works yet. Inverse Relationships and UI-Update not working? is the closest I have found yet, but still does not fix the issue.
EDIT
I can force it to rebind like so:
ListView.ItemsSource = null;
ListView.ItemsSource = things;
But that is not optimal. I am trying to take advantage of Realm's "live objects" where the collection should always know when items are changed or added.
EDIT 2
Setting BindingMode=OneWay in code-behind also does not change the behavior:
_realm = Realm.GetInstance();
things = (IRealmCollection<Thing>)_realm.All<Thing>();
var binding = new Binding
{
Source = things,
Mode = BindingMode.OneWay
};
ListView.SetBinding(ListView.ItemsSourceProperty, binding);
SOLUTION
It turned out to be a known issue in IRealmCollection: https://github.com/realm/realm-dotnet/issues/1461#issuecomment-312489046 which is fixed in Realm 1.6.0. I have updated to the pre-release NuGet package and can confirm that the ListView now updates as expected.
Set Mode=OneWay in Binding
Method 1: In Xaml
<ListView ItemsSource="{x:Bind things, Mode=OneWay}" />
Method 2: In Code Behind
Binding myBind = new Binding();
myBind.Source = things;
myBind.Mode = BindingMode.OneWay;
myListView.SetBinding(ListView.ItemsSourceProperty, myBind);
It is a bug in IRealmCollection. You can use Prerelease Nuget to solve it.
For more info:
IRealmCollection does not update UWP ListView
GitHub Issue: IRealmCollection does not update UWP ListView
Related
I'm doing a binding in UWP, the listview is not showing(so it's working fine), but the header is still on the view.
So the problem is that the header is not getting the binding from the PivotItem, what can be the problem?
<PivotItem Header="Hello" Visibility="{Binding isVisible, Converter={StaticResource Visibility}}">
<ListView ItemsSource="{Binding myList}"/>
</PivotItem>
This is actually a bit tricky. Setting Visibility on a PivotItem does indeed hide only the contents of the item, not the PivotItem itself. That said, you can hide it from the code-behind by removing it from the pivot completely:
MyPivot.Items.Remove(HideablePivotItem);
The problem is now the fact that you need to trigger it on binding change. For that purpose I suggest you use a custom Behavior and a CallMethodAction.
First install the Microsoft.Xaml.Behaviors.Uwp.Managed from NuGet (right-click your project, click Manage NuGet Packages... find the package using search and click Install.
Now, create a new class DataChangeTriggerBehavior class:
public class DataChangeTriggerBehavior : Trigger<FrameworkElement>
{
public static readonly DependencyProperty BindingProperty = DependencyProperty.Register(
nameof(Binding), typeof(object), typeof(DataChangeTriggerBehavior), new PropertyMetadata(null, BindingChanged));
public object Binding
{
get => (object)GetValue(BindingProperty);
set => SetValue(BindingProperty, value);
}
private static void BindingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
DataChangeTriggerBehavior changeTrigger = (DataChangeTriggerBehavior)dependencyObject;
if (changeTrigger.AssociatedObject == null) return;
Interaction.ExecuteActions(changeTrigger.AssociatedObject, changeTrigger.Actions, args);
}
}
This behavior will observe a binding and trigger its associated actions whenever the binding changes.
Now, update your Page element as follows:
<Page
...
x:Name="Page"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:customBehavior="using:XXX"
mc:Ignorable="d">
Where XXX is the namespace where your behavior is defined.
Now use the behavior in your Pivot:
<Pivot x:Name="MyPivot">
<interactivity:Interaction.Behaviors>
<local:DataChangeTriggerBehavior Binding="{Binding isVisible}">
<core:CallMethodAction MethodName="TogglePivotItem"
TargetObject="{Binding ElementName=Page}" />
</local:DataChangeTriggerBehavior>
</interactivity:Interaction.Behaviors>
<PivotItem Header="Hello" Visibility="Collapsed" x:Name="HideablePivotItem">
<ListView ItemsSource="{Binding myList}"/>
</PivotItem>
</Pivot>
Finally you must define the TogglePivotItem method in your page's code-behind:
private int originalPosition = 0;
public void TogglePivotItem()
{
if (MyPivot.Items.Contains(HideablePivotItem))
{
//store the position of the item to be readded later
originalPosition = MyPivot.Items.IndexOf(HideablePivotItem);
MyPivot.Items.Remove(HideablePivotItem);
}
else
{
MyPivot.Items.Insert(originalPosition, HideablePivotItem);
}
}
I am storing the original position of the PivotItem so that it can be re-added to the same place again.
Oxyplot graphs 13 points which are derived from the 6 user input text boxes. The values in the text boxes are held in public variables in the MainWindow.xaml.cs class. The variables are updated when the user presses enter in the text box. How would I make the refresh button refresh the graph.
private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
//Refresh The Graph
}
I think that this would be done using the
PlotModel.RefreshPlot()
method, but I am not sure how to implement it because of Oxyplot's poor documentation.
I just updated to a new version of OxyPlot via NuGet. I'm using OxyPlot.Wpf v20014.1.277.1 and I think you now need to call InvalidatePlot(bool updateData) on the PlotModel instead of RefreshPlot (which is no longer available). I tested this in my sample code and it worked as expected.
If you want to refresh the plot and update the data collections, you need to pass true to the call:
PlotModel.InvalidatePlot(true)
Give x:Name to OxyPlot instance in XAML:
<oxy:Plot x:Name="Plot1"/>
and on button click handler, refresh like this:
private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
Plot1.RefreshPlot(true);
}
The cleanest way I've found to get "sort of" auto-update is reacting to CollectionChanged on the collection that is LineSeries' ItemsSource.
In ViewModel:
ObservableCollection<DataPoint> Data { get; set; }
= new ObservableCollection<DataPoint>();
public PlotModel PlotModel
{
get { return _plot_model; }
set
{
_plot_model = value;
RaisePropertyChanged(() => PlotModel);
}
}
PlotModel _plot_model;
// Inside constructor:
Data.CollectionChanged += (a, b) => PlotModel.InvalidatePlot(true);
In the current OxyPlot.Wpf (1.0.0-unstable1983) you have two options:
Bind the Series.ItemsSource property from XAML to a collection in your viewmodel and exchange the whole collection, when you need an update. This also allows for concurrent async updates with larger data sets.
Bind the Plot.InvalidateFlag property of type int to your viewmodel and increment whenever you need an update. I haven't tested this approach, though.
The following code illustrates both options (pick one). XAML:
<oxy:Plot InvalidateFlag="{Binding InvalidateFlag}">
<oxy:Plot.Series>
<oxy:LineSeries ItemsSource="{Binding DataSeries}" />
</oxy:Plot.Series>
</oxy:Plot>
Updates on the ViewModel:
private async Task UpdateAsync()
{
// TODO do some heavy computation here
List<DataPoint> data = await ...
// option 1: Trigger INotifyPropertyChanged on the ItemsSource.
// Concurrent access is ok here.
this.DataSeries = data; // switch data sets
// option 2: Update the data in place and trigger via flag
// Only one update at a time.
this.DataSeries.Clear();
data.ForEach(this.DataSeries.Add);
this.InvalidateFlag++;
}
After having the same question with the same issue, it would seem that the only working solution (at least to my point of view) is as followed :
PlotView.InvalidatePlot(true)
Doing so, after updating one or multple Series do refresh your PlotView.
The refresh rate depends on how often, or at which rate your serie(s) is/are updated.
Here is a code snippet (on Xamarin Android but should work anyway) :
PlotView resultsChart = FindViewById<PlotView>(Resource.Id.resultsChart);
PlotModel plotModel = new PlotModel
{
// set here main properties such as the legend, the title, etc. example :
Title = "My Awesome Real-Time Updated Chart",
TitleHorizontalAlignment = TitleHorizontalAlignment.CenteredWithinPlotArea,
LegendTitle = "I am a Legend",
LegendOrientation = LegendOrientation.Horizontal,
LegendPlacement = LegendPlacement.Inside,
LegendPosition = LegendPosition.TopRight
// there are many other properties you can set here
}
// now let's define X and Y axis for the plot model
LinearAxis xAxis = new LinearAxis();
xAxis.Position = AxisPosition.Bottom;
xAxis.Title = "Time (hours)";
LinearAxis yAxis = new LinearAxis();
yAxis.Position = AxisPosition.Left;
yAxis.Title = "Values";
plotModel.Axes.Add(xAxis);
plotModel.Axes.Add(yAxis);
// Finally let's define a LineSerie
LineSeries lineSerie = new LineSeries
{
StrokeThickness = 2,
CanTrackerInterpolatePoints = false,
Title = "Value",
Smooth = false
};
plotModel.Series.Add(lineSerie);
resultsChart.Model = plotModel;
Now, whenever you need to add DataPoints to your LineSerie and to updated automatically the PlotView accordingly, just do as followed :
resultsChart.InvalidatePlot(true);
Doing so will automatically refresh your PlotView.
On a side note, the PlotView will also be updated when an event occurs such as a touch, a pinch to zoom, or any kind of UI-related events.
I hope I could help. I had trouble with this for a very long time.
Exists three alternatives how refresh plot (from OxyPlot documentation):
Change the Model property of the PlotView control
Call Invalidate on the PlotView control
Call Invalidate on the PlotModel
Another two years later... this solution works for me, because I have no oxyplot models and I´m missing some of the named functions from above.
code behind:
public partial class LineChart : UserControl
{
public LineChart()
{
InitializeComponent();
DataContext = this;
myChart.Title = "hier könnte Ihr Text stehen!";
this.Points = new List<DataPoint>();
randomPoints();
}
public IList<DataPoint> Points { get; private set; }
public void randomPoints()
{
Random rd = new Random();
String myText = "";
int anz = rd.Next(30, 60);
for (int i = 0; i < anz; i++)
myText += i + "," + rd.Next(0, 99) + ";";
myText = myText.Substring(0, myText.Length - 1);
String[] splitText = myText.Split(';');
for (int i = 0; i < splitText.Length; i++)
{
String[] tmp = splitText[i].Split(',');
Points.Add(new DataPoint(Double.Parse(tmp[0].Trim()), Double.Parse(tmp[1].Trim())));
}
while (Points.Count > anz)
Points.RemoveAt(0);
myChart.InvalidatePlot(true);
}
}
To update your data don't exchange the whole IList, rather add some new DataPoints to it and remove old ones at position 0.
XAML:
<UserControl x:Class="UxHMI.LineChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UxHMI"
xmlns:oxy="http://oxyplot.org/wpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="Container" Background="White">
<oxy:Plot x:Name="myChart" Title="{Binding Title}" FontFamily="Bosch Sans Medium" Foreground="#FF0C6596" FontSize="19" Canvas.Left="298" Canvas.Top="32" Background="AliceBlue" Margin="0,0,10,0">
<oxy:Plot.Series>
<oxy:LineSeries x:Name="ls" Background="White" ItemsSource="{Binding Points}" LineStyle="Solid" Color="ForestGreen" MarkerType="None" MarkerSize="5" MarkerFill="Black">
</oxy:LineSeries>
</oxy:Plot.Series>
</oxy:Plot>
<Button x:Name="button" Content="Random" HorizontalAlignment="Left" Margin="0,278,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
important are the x:Name="myChart" and ItemsSource="{Binding Points}"
I hope this is useful for someone out there
I am developing a WPF application that follows MVVM. Now I am handling navigation of views in the following manner.
MainWindow View
<Border>
<StackPanel>
<local:Home
Content="{Binding CurrentView,Converter={StaticResource ViewConverterHome}, UpdateSourceTrigger=PropertyChanged}"/>
<local:Page1
Content="{Binding CurrentView,Converter={StaticResource ViewConverterPage1}, UpdateSourceTrigger=PropertyChanged}"/>
<local:Page2
Content="{Binding CurrentView,Converter={StaticResource ViewConverterPage2}, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</Border>
Home, Page1,Page2 are 3 views. HomeVM,Page1VM,Page2VM are view models corresponding to the views. There is a class call ApplicationViewModel that contains a property CurrentView of type CViewModelBase which is the parent class for all three viewmodels. ApplicationViewModel handles the navigation in the folowing manner
private void OnUserInputNextClicked(object sender, OperationInformationChangedEventArgs e)
{
do
{
if (this.CurrentView is HomeVM)
{
this.CurrentView = null;
Page1VM page1 = new Page1VM("BNM", "MATH HONS", "13");
page1.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
page1.BackCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputBackClicked);
this.CurrentView = page1;
break;
}
if (this.CurrentView is Page1VM)
{
this.CurrentView = null;
Page2VM page2 = new Page2VM("Kolkata", "Monoj", "Itachuna");
page2.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
page2.BackCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputBackClicked);
this.CurrentView = page2;
break;
}
if (this.CurrentView is Page2VM)
{
this.CurrentView = null;
HomeVM home = new HomeVM("Anirban", "30");
home.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
this.CurrentView = home;
break;
}
} while (false);
}
The navigation is working perfectly; But dispose of disappeared views are not getting called.So all the views live till the end. Is there any way to prevent that?
Your Views will always exist because you added a copy of each one to your UI with the XAML, even if the Content contained in them may not exist
Typically I will use a ContentControl to display content instead of creating an instance of the control for each content type, and I'll use DataTemplates to tell WPF how to draw each type of content.
For example,
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeVM}">
<local:Home Content="{Binding }" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:Page1VM}">
<local:Page1 Content="{Binding }" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:Page2VM}">
<local:Page2 Content="{Binding }" />
</DataTemplate>
</Window.Resources>
<Border>
<StackPanel>
<ContentControl Content="{Binding CurrentView}" />
</StackPanel>
</Border>
This way, you only have one instance of your Content in the VisualTree, and the DataTemplate WPF users to draw your content changes based on it's DataType.
I have an example of this kind of navigation with WPF on my blog if you're interested in checking out a full code sample
You need to change DataContext of MainWindow. It depends on your integration. When I make a MVVM application what I do is that pass MainWindow object to every view constructor. And whenever I have to move to next page (like on next button) I change the MainWindow object DataContext to new view.
Something like this.
public PageOneViewModel
{
private MainWindow _mainWindow;
public PageOneViewModel(MainWindow mainWindow)
{
// Here I am saving MainWindow object.
_mainWindow = mainWindow;
}
public OnNext()
{
// Here I am changing the view.
MainWindow.DataContext = new PageTwoViewModel(_mainWindow);
}
}
Have you considered using Frame?
<Frame Name="YourFrame" Navigated="OnNavigated"/>
and then you can call
YourFrame.CanGoBack(), YourFrame.GoBack()
etc.
Here's a link to my answer to a similar question with working source code. The technique I used is a little similar to Faisal's solution.
If you need a good downloadable sample solution that demonstrates navigation using a side menu, look at here and here(simpler example).
I am quite new to Windows development and of course even newer to Metro style app development. I am not sure I understand how Data Binding works.
I have a list of items.
private List<Expense> _expenses = new List<Expense>();
public List<Expense> Items
{
get
{
return this._expenses;
}
}
Which I bind to the XAML. (I use the Split Page template)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DefaultViewModel["Items"] = _data.Items;
}
Then I display it
<UserControl.Resources>
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items, Mode=TwoWay}"/>
</UserControl.Resources>
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
Margin="120,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
SelectionChanged="ItemListView_SelectionChanged"
ItemTemplate="{StaticResource DefaultListItemTemplate}"/>
Which works fine. Then when the user clicks on a Button I add a new item to my list
_data.Items.Add(new Expense
{
Total = 100,
When = new DateTime(2013, 6, 6),
For = "Myself"
});
I was expecting that the ListView would refresh automagically since I set Mode=TwoWay but it does not. Did I misunderstand the concept and it is not possible for the list to refresh? Otherwise, what could I have done wrong?
In order to have the UI update after you make changes to the collection you need it to implement INotifyCollectionChanged. This will notify the UI when a change occurs and it will respond by rebinding the UI on top of the change.
Implementing this interface is fairly involved though. Instead you should just use ObservableCollection<T> in place of List<T> and the scenario should work just fine
private ObservableCollection<Expense> _expenses = new ObservableCollection<Expense>();
public ObservableCollection<Expense> Items
{
get
{
return this._expenses;
}
}
I need to write a small application to read a configuration file and generate some report with it. I was hoping to finally use MVVM but it's quite tricky to get started. Oh, I'm using Caliburn.Micro framework.
So this is what I have, a shell (primary view that hosts other views) that has a ribbon with 3 buttons on it:
1) Open file
2) Show settings
3) Show results
And two other views, SettingsView and ResultsView with buttons to generate and delete a report.
So I guess the view structure would be like this:
ShellView
Ribbon
OpenFileButton
SettingsButton
ResultsButton
ContentControl (hosts SettingsView and ResultsView)
SettingsView
CalculateResultsButton
ResultsView
CancelResultsButton
The tricky part is this:
1. "Show settings" button is disabled until a file is opened (via Open file).
2. "Show results" button is disabled until a report is calculated (via a
method in SettingsViewModel).
3. If a report is calculated, the CalculateResultsButton is disabled and
CancelResultsButton is enabled and vice versa.
Please advise how could I achieve this ? I've no ideas what strategy should I go for. My non-MVVM-thinking-brain says that I should create a status variable and then somehow bind those buttons to that variable, but I guess that wont work in a MVVM world, right ? Any code example would be very very very appreciated!
Many thanks!
Since you're using CM you won't need any code-behind. You can delete the .xaml.cs files if you want.
This is a pretty basic example but it should give you an idea on how to control the state of the buttons. In this example, Open will be enabled and the other two are disabled. If you click on Open, Settings is enabled. The same happens with Results once Settings is clicked.
If you need a way to do global state the same concept can be applied by injecting a singleton, SharedViewModel, into the ViewModels and the CanXXX methods can check values in SharedViewModel. This is a SL demo of different things but one is injecting a singleton to share data, the same idea applies in wpf.
ShellView:
<Window x:Class="CMWPFGuardSample.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0"
Orientation="Horizontal">
<Button x:Name="Open"
Content="Open" />
<Button x:Name="Settings"
Content="Settings" />
<Button x:Name="Results"
Content="Results" />
</StackPanel>
</Grid>
</Window>
ShellViewModel:
[Export(typeof (IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
private bool _isOpen;
public bool IsOpen
{
get { return _isOpen; }
set
{
_isOpen = value;
NotifyOfPropertyChange(() => IsOpen);
NotifyOfPropertyChange(() => CanSettings);
}
}
private bool _isSettings;
public bool IsSettings
{
get { return _isSettings; }
set
{
_isSettings = value;
NotifyOfPropertyChange(() => IsSettings);
NotifyOfPropertyChange(() => CanResults);
}
}
public bool IsResults { get; set; }
public void Open()
{
IsOpen = true;
}
public bool CanSettings
{
get { return IsOpen; }
}
public void Settings()
{
IsSettings = true;
}
public bool CanResults
{
get { return IsSettings; }
}
public void Results()
{
}
}
MVVM and WPF Commands perfectly fits your "tricky part" requirements since have built in ICommand.CanExecute() method which allows enabling/disabling corresponding button based on custom logic.
To use this naice feature take a look first at the RoutedCommand Class and self explanatory example on MSDN How to: Enable a Command (see below code snippets).
And in general about MVVM, it is really SIMPLE! Just try it and you won't leave without it ;) In few words - you have to create for each EntityView.xaml corresponding EntityViewModel class and then just put instance of it in the View's DataContext either explicitly in code or using bindings:
var entityViewModel = new EntityViewModel();
var view = new EntityView();
view.DataContext = entityViewModel;
MVVM Command and Command.CanExecute bindings:
XAML:
<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CloseCommand"
Name="RootWindow"
>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="CloseCommandHandler"
CanExecute="CanExecuteHandler"
/>
</Window.CommandBindings>
<StackPanel Name="MainStackPanel">
<Button Command="ApplicationCommands.Close"
Content="Close File" />
</StackPanel>
</Window>
C# code behind:
// Create ui elements.
StackPanel CloseCmdStackPanel = new StackPanel();
Button CloseCmdButton = new Button();
CloseCmdStackPanel.Children.Add(CloseCmdButton);
// Set Button's properties.
CloseCmdButton.Content = "Close File";
CloseCmdButton.Command = ApplicationCommands.Close;
// Create the CommandBinding.
CommandBinding CloseCommandBinding = new CommandBinding(
ApplicationCommands.Close, CloseCommandHandler, CanExecuteHandler);
// Add the CommandBinding to the root Window.
RootWindow.CommandBindings.Add(CloseCommandBinding);