I have a user control which has a CheckBox, a Button, and a CommandBinding. If the CheckBox is checked, the Button is enabled. The MainWindow uses the UserControl. When the Button in the main window is pressed, the UserControl is removed from UI, and GC.Collect() is called, but CanExecute method still runs.
I find that if I click the button in main window twice, CanExecute will no longer run. It seems that I don't call GC.Collect() at the right time.
I want to know what is the good timing to call GC to clean the unused user control, so that CanExecute will not be called.
XAML
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<RoutedUICommand x:Key="okCommand" Text="OK"/>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding Command="{StaticResource okCommand}" CanExecute="CommandBinding_CanExecute_1"/>
</UserControl.CommandBindings>
<StackPanel>
<CheckBox Name="checkBox" Content="CheckBox"/>
<Button Command="{StaticResource okCommand}" Content="{Binding Path=Text, Source={StaticResource okCommand}}"/>
</StackPanel>
</UserControl>
Code behind
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void CommandBinding_CanExecute_1(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = checkBox.IsChecked.GetValueOrDefault(false);
System.Media.SystemSounds.Beep.Play();
}
}
MainWindow
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Loaded="Window_Loaded_1">
<StackPanel>
<Border Name="container"/>
<Button Content="Set Null" Click="Button_Click_1"/>
</StackPanel>
</Window>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
container.Child = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
UserControl1 uc = new UserControl1();
container.Child = uc;
}
}
Use grid as container and Container.Clear() method and forget about GC.
I find another solution. That is to call CommandBindings.Clear() in UserControl1 when it unloads.
I believe this is a neat way, since the caller of UserControl1 doesn't take care of the cleaning job of UserControl1.
Related
I have one "login page" and one "content page". The login page consists of a PasswordBox and a Button. When the button is clicked or the Enter-key is pressed in the PasswordBox, I want the program to navigate to the next page. Navigating with the button works fine, but when the page is changed due to the pressed enter key, the Button on the next page is focused. How can I disable/avoid this behaviour?
"Focused" button:
MainPage.xaml
<Page
x:Class="TabNavigation.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TabNavigation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<PasswordBox x:Name="textBox" KeyDown="HandleTextBox_KeyDown"/>
<Button x:Name="loginButton" Content="Einloggen" Click="HandleLoginButton_Click"/>
</StackPanel>
</Grid>
</Page>
MainPage.xaml.cs
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
namespace TabNavigation {
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
}
private void HandleTextBox_KeyDown(object sender, KeyRoutedEventArgs e) {
if(e.Key == Windows.System.VirtualKey.Enter) {
this.Frame.Navigate(typeof(ContentPage));
}
}
private void HandleLoginButton_Click(object sender, RoutedEventArgs e) {
this.Frame.Navigate(typeof(ContentPage));
}
}
}
ContentPage.xaml
<Page
x:Class="TabNavigation.ContentPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TabNavigation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<Button>Test</Button>
</StackPanel>
</Grid>
</Page>
You can cancel the focus in GettingFocus:
<Button GettingFocus="Button_GettingFocus">Test</Button>
private void Button_GettingFocus(UIElement sender, GettingFocusEventArgs args)
{
args.Cancel = true;
}
Old answer:
You have few options:
Disable focus on button with IsTabStop=false
Change TabIndex to larger integer than other elements.
Set focus from your code to something else: otherControl.Focus(FocusState.Programmatic);
I'm new to WPF so bear with me. I have a WinForms Application that I am trying to redo in WPF. In my current WinForms Application, I stick all my Controls into one Form, and hide/show them based on what buttons are hit, as well as making use of a second form.
My goal: Create different views to switch between smoothly based on what button is hit, instead of hiding Controls or making separate Forms and then hiding those.
I currently have a MainWindow view (My initial launch window), where with a button, I switch to my CreateAccount view. What I am having issues with is, how can I make my button in my CreateAccount go "back" to my MainWindow?
My end goal is to be able to switch between 4 views based off Button clicks.
Here is my MainWindow.xaml
<Window x:Class="MusicPlayer.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MusicPlayer"
xmlns:Views="clr-namespace:MusicPlayer.Views"
xmlns:ViewModels="clr-namespace:MusicPlayer.ViewModels"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Name="CreateAccountTemplate" DataType="{x:Type ViewModels:CreateAccountViewModel}">
<Views:CreateAccountView DataContext="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Button x:Name="TestButton" Content="Button" HorizontalAlignment="Left" Margin="164,182,0,0" VerticalAlignment="Top" Height="61" Width="68" Click="CreateAccountView_Clicked"/>
<PasswordBox HorizontalAlignment="Left" Margin="164,284,0,0" VerticalAlignment="Top" Width="120"/>
<ContentPresenter Content="{Binding}"/>
</Grid>
</Window>
My MainWindow.xaml.cs
using System;
using System.Windows;
using MusicPlayer.ViewModels;
namespace MusicPlayer {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
protected override void OnClosed(EventArgs e) {
base.OnClosed(e);
Application.Current.Shutdown();
} //end of onClosed
private void CreateAccountView_Clicked(object sender, RoutedEventArgs e) {
DataContext = new CreateAccountViewModel();
} //end of CreateAccountView_Clicked
}
}
And here is my CreateAccount.xaml
<UserControl x:Class="MusicPlayer.Views.CreateAccountView"
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:Views="clr-namespace:MusicPlayer.Views"
xmlns:ViewModels="clr-namespace:MusicPlayer.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
</UserControl.Resources>
<Grid Background="White">
<Button Content="Button" HorizontalAlignment="Left" Margin="276,279,0,0" VerticalAlignment="Top" Height="60" Width="59" Click="Button_Click"/>
</Grid>
</UserControl>
And my CreateAccountView.xaml.cs
using System.Windows;
using System.Windows.Controls;
using MusicPlayer.ViewModels;
namespace MusicPlayer.Views {
public partial class CreateAccountView : UserControl {
//public static readonly DependencyProperty TestMeDependency = DependencyProperty.Register("MyProperty", typeof(string), typeof(CreateAccountView));
public CreateAccountView() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
DataContext = new MainWindowViewModel();
}
}
}
It seems to me that your current attempt is on the right track. The main issue with the code you posted is that the CreateAccountView.Button_Click() handler doesn't have access to the DataContext property it should be setting:
private void Button_Click(object sender, RoutedEventArgs e) {
DataContext = new MainWindowViewModel();
}
This DataContext property belongs to the CreateAccountView user control. However, this is not the controlling context for what's being displayed. So changing the value of that DataContext property doesn't have any useful effect. (Indeed, a user control should not set its own DataContext property at all, because doing so discards whatever context the client code using that user control had set.)
There's not enough context to know exactly what the best way for you to do this would be. I don't think it would be possible to provide enough context here on Stack Overflow. The overall architecture will depend on too many little details about your program. But, one way to approach this which I think is a good one would be this:
Create a "main" view model that governs the overall behavior of the app
Create individual view models that relate to different states of the UI
Have the main view model configure the individual view models to switch the current view model as appropriate, given the user input (e.g. clicking buttons)
Translating that into code, looks something like this…
First, the view models:
class MainViewModel : NotifyPropertyChangedBase
{
private object _currentViewModel;
public object CurrentViewModel
{
get => _currentViewModel;
set => _UpdateField(ref _currentViewModel, value);
}
private readonly HomeViewModel _homeViewModel;
private readonly Sub1ViewModel _sub1ViewModel;
private readonly Sub2ViewModel _sub2ViewModel;
public MainViewModel()
{
_sub1ViewModel = new Sub1ViewModel
{
BackCommand = new DelegateCommand(() => CurrentViewModel = _homeViewModel)
};
_sub2ViewModel = new Sub2ViewModel
{
BackCommand = new DelegateCommand(() => CurrentViewModel = _homeViewModel)
};
_homeViewModel = new HomeViewModel
{
ShowSub1Command = new DelegateCommand(() => CurrentViewModel = _sub1ViewModel),
ShowSub2Command = new DelegateCommand(() => CurrentViewModel = _sub2ViewModel)
};
CurrentViewModel = _homeViewModel;
}
}
class HomeViewModel : NotifyPropertyChangedBase
{
private ICommand _showSub1Command;
public ICommand ShowSub1Command
{
get => _showSub1Command;
set => _UpdateField(ref _showSub1Command, value);
}
private ICommand _showSub2Command;
public ICommand ShowSub2Command
{
get => _showSub2Command;
set => _UpdateField(ref _showSub2Command, value);
}
}
class Sub1ViewModel : NotifyPropertyChangedBase
{
private ICommand _backCommand;
public ICommand BackCommand
{
get => _backCommand;
set => _UpdateField(ref _backCommand, value);
}
}
class Sub2ViewModel : NotifyPropertyChangedBase
{
private ICommand _backCommand;
public ICommand BackCommand
{
get => _backCommand;
set => _UpdateField(ref _backCommand, value);
}
}
Of course, these view models contain only the implementation details needed to handle the UI switching. In your program, each would also include the stuff specific to each view state that you need.
In my little sample, the "home" view contains a couple of buttons, used to select the individual sub-views available:
<UserControl x:Class="WpfApp1.HomeView"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Home: "/>
<Button Content="Sub1" Command="{Binding ShowSub1Command}"/>
<Button Content="Sub2" Command="{Binding ShowSub2Command}"/>
</StackPanel>
</UserControl>
The sub views just contain the button required to go back to the home view:
<UserControl x:Class="WpfApp1.Sub1View"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Sub1 View: "/>
<Button Content="Back" Command="{Binding BackCommand}"/>
</StackPanel>
</UserControl>
<UserControl x:Class="WpfApp1.Sub2View"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Sub2 View: "/>
<Button Content="Back" Command="{Binding BackCommand}"/>
</StackPanel>
</UserControl>
Finally, the main window sets the main view model, and declares templates to use for each of the specific sub views:
<Window x:Class="WpfApp1.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type l:HomeViewModel}">
<l:HomeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type l:Sub1ViewModel}">
<l:Sub1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type l:Sub2ViewModel}">
<l:Sub2View/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ContentControl Content="{Binding CurrentViewModel}"/>
</StackPanel>
</Window>
Importantly, you'll see that none of the view objects include any code-behind. It's not necessary when you approach the problem this way, at least not for the purpose of controlling basic behaviors in the code. (You may still wind up with code-behind for view objects, but this will usually only be for the purpose of implementing specific user-interface behaviors unique to that view object, not for dealing with the view model state.)
Using this approach, you let WPF do as much of the heavy-lifting as possible. It also decouples all of the view model objects from each other. There's a clear hierarchy: only the top-level "main" view model even knows about the other view models. This allows the sub-view models ("home", "sub1", and "sub2") to be reused as necessary in other scenarios without any modification or special-case handling within them.
Here are the helper classes I used above:
class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class DelegateCommand : ICommand
{
private readonly Action _execute;
public DelegateCommand(Action execute)
{
_execute = execute;
}
#pragma warning disable 67
public event EventHandler CanExecuteChanged;
#pragma warning restore
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => _execute();
}
I am developing a wpf application for the surface pro in tablet mode. I am coding on a different computer and there everything works fine. When testing the application on the surface pro something weird happens:
During the application a second window gets opened, in order to modify some settings. This window includes a button in order to close the window (see code below). When this button is clicked on the surface pro the whole application gets closed (including the main window). On the computer where I am writing the code this never happens, so in my opinion the problem lies with the hardware.
Thank you for your help!
Edit 21/03/2018
So as discussed in the comments I have tried several things and the problem remains. I have now deleted most of the application code such that only the essential feature remain and the problem still hasn't disappeared. I will post the code below:
App.xaml
<Application x:Class="TestNamespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestNamespace"
Startup="ApplicationStartup">
<Application.Resources>
<Style TargetType="{x:Type Window}">
<Setter Property="FontFamily" Value="Segoe UI" />
</Style>
</Application.Resources>
</Application>
App.xaml.cs
public partial class App : Application
{
public MainWindow window = new MainWindow();
public Monitoring monitoring;
private void ApplicationStartup(object sender, StartupEventArgs e)
{
window.Show();
monitoring = new Monitoring();
window.Content = monitoring.gui;
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine("App1: There has been an unhandled exception");
throw new NotImplementedException();
}
private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine("App2: There has been an unhandled exception");
throw new NotImplementedException();
}
}
GUI.xaml
<UserControl x:Class="TestNamespace.GUI"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mi="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:local="clr-namespace:TestNamespace">
<Grid Background="Black">
<Button HorizontalAlignment="Center" VerticalAlignment="Center"
Width="300" Height="300"
Content="NewWindow" Click="SettingsButton_Click"/>
</Grid>
</UserControl>
GUI.xaml.cs
public partial class GUI : UserControl
{
private Monitoring monitoring;
public GUI(Monitoring monitoring)
{
this.monitoring = monitoring;
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine(" GUI: There has been an unhandled exception");
throw new NotImplementedException();
}
private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
monitoring.settingsWindow = new testWindow();
monitoring.settingsWindow.Show();
}
}
Monitoring.cs
public class Monitoring
{
private App currentApp = (App)Application.Current;
public GUI gui;
public Window settingsWindow;
public Monitoring()
{
gui = new GUI(this);
}
}
TestWindow.xaml
<Window x:Class="TestNamespace.testWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestNamespace"
mc:Ignorable="d"
Title="testWindow"
ResizeMode="NoResize" WindowState="Maximized" WindowStyle="None">
<Grid>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="245,200,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
</Window>
TestWindow.xaml.cs
public partial class testWindow : Window
{
public testWindow()
{
InitializeComponent();
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
System.Diagnostics.Debug.WriteLine("TestWindow: There has been an unhandled exception");
throw new NotImplementedException();
}
private void button_Click(object sender, RoutedEventArgs e)
{
e.Handled = true;
this.Close();
}
}
MainWindow.xaml
<Window x:Class="TestNamespace.MainWindow"
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:TestNamespace"
mc:Ignorable="d"
ResizeMode="NoResize" WindowStartupLocation="CenterScreen" WindowState="Maximized" WindowStyle="None">
<Grid Background="White">
<TextBox x:Name="textBox" HorizontalAlignment="Center" Height="47" TextWrapping="Wrap" Text="LOADING..." VerticalAlignment="Center" Width="198" FontWeight="Bold" FontSize="36" BorderBrush="{x:Null}" />
</Grid>
</Window>
MainWindow.xaml.cs
partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
This is the complete code for the Minimal, Complete, and Verifiable example. This code still produces the error on the tablet. Thank you for your help!
I finally managed to solve the problem! Instead of creating and showing a new window, I created a new UserControl (TestWindow) and changed the content of the mainWindow. Upon closing the TestWindow, the normal GUI is loaded as Content of the MainWindow and the TestWindow is set to null.
It might not be the best solution, but it works.
EDIT 1
A few weeks later I stumbled upon the same problem once again. I found a solution written by Erti-Chris Eelmaa that finally solved the problem. I needed to change the Application.ShutdownMode such that the application only shuts down when Application.Shutdown(); is explicitly called.
Application.ShutdownMode = ShutdownMode.OnExplicitShutdown;
I hope this helps!
I have a checkbox in my datatemplate and for some reason the events are not firing. see code below. my datatemplate is in a resource dictionary with code behind file. Any Ideas?
<ResourceDictionary x:Class="ArmyBuilder.Templates.EquipmentDataTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<DataTemplate x:Key="EquipmentDataTemplate">
<Grid>
<CheckBox Content="{Binding Name}" Checked="ToggleButton_OnChecked" Click="CheckBox_Click"/>
</Grid>
</DataTemplate>
//code behind
namespace ArmyBuilder.Templates
{
public partial class EquipmentDataTemplate : ResourceDictionary
{
public EquipmentDataTemplate()
{
InitializeComponent();
}
private void ToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
// breakpoint not hit
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
// breakpoint not hit
}
}
}
I am not sure how you use it, but the your code works for me and the click event got fired. Check the following and if you still cannot find the point, share a repro project to show how you used it.
Template XAML:
<ResourceDictionary x:Class="App10.EquipmentDataTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<DataTemplate x:Key="EquipmentDataTemplate">
<Grid>
<CheckBox Content="Click Me" Checked="ToggleButton_OnChecked" Click="CheckBox_Click"/>
</Grid>
</DataTemplate>
</ResourceDictionary>
Template cs:
namespace App10
{
public sealed partial class EquipmentDataTemplate : ResourceDictionary
{
public EquipmentDataTemplate()
{
this.InitializeComponent();
}
private void ToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
// breakpoint not hit
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
// breakpoint not hit
}
}
}
In MainPage.Xaml, use the template in a ListView:
<Page
x:Class="App10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App10"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:EquipmentDataTemplate></local:EquipmentDataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="listView" CanReorderItems="True" AllowDrop="True" ItemTemplate="{StaticResource EquipmentDataTemplate}">
</ListView>
</Grid>
</Page>
In MainPage cs:
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();
var list = new ObservableCollection<string>();
for (int i = 0; i < 10; i++)
{
list.Add("Item " + i);
}
listView.ItemsSource = list;
}
}
}
I have created a UserControl that has a command (DeleteCommand) inside:
public partial class TestControl : UserControl
{
public static RoutedCommand DeleteCommand = new RoutedCommand();
private void DeleteCommandExecute(object sender, ExecutedRoutedEventArgs e)
{
}
private void DeleteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public TestControl()
{
InitializeComponent();
CommandBinding deleteCommandBinding = new CommandBinding(DeleteCommand, DeleteCommandExecute, DeleteCommandCanExecute);
this.CommandBindings.Add(deleteCommandBinding);
}
}
I have put this UserControl inside a Window:
<Window x:Class="TestRoutedCommand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestRoutedCommand"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Fire event" Margin="156,29,205,254" Command="{x:Static local:TestControl.DeleteCommand}" />
<local:TestControl Margin="126,135,135,46"/>
</Grid>
</Window>
There is also a Button which is using the DeleteCommand. My problem is that this button is always disabled and the DeleteCommandCanExecute handler is never called, although e.CanExecute is always set to true.
I have tried to call:
CommandManager.InvalidateRequerySuggested();
but nothing happens. The event is never fired. Maybe I am doing the CommandBinding wrong.
What I want to achieve is that when the user clicks on the button that the DeleteCommandExecute handler is fired. My goal is to create commands for my MenuButtons which will trigger some methods in my UserControls which can be deep in the Visual Tree.
Slightly change your XAML:
<Grid>
<Button Content="Fire event" Margin="156,29,205,254" Command="{x:Static local:TestControl.DeleteCommand}" CommandTarget="{Binding ElementName=Control1}" />
<local:TestControl x:Name="Control1" Margin="126,135,135,46"/>
</Grid>
CommandTarget says where to find needed handlers.