How to add event to control inside TemplatedControl - c#

I have a TemplatedControl and some daughter controls inside it. I want to assign them some events. Initially axaml file cannot access C# module, but when I add x:Class="MyNamespace.MyTemplatedControl" to axaml, although C# code is seen from it, an error occurs:
MyTemplatedControl.axaml(9, 6): [XAMLIL] No Content property or any Add methods found for type MyDesktopApp:MyNamespace.MyTemplatedControl Line 9, position 6.
Looking for solution, all I have found was this variant with Button and its Command property. But in this case I will be restricted only with click event, without opportunity to handle text changed, drag and drop, getting and loosing input focus and other popular actions.
MyTemplatedControl.axaml:
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:MyNamespace"
x:Class="MyNamespace.MyTemplatedControl">
<Design.PreviewWith>
<controls:MyTemplatedControl />
</Design.PreviewWith>
<Style Selector="controls|MyTemplatedControl">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<StackPanel>
<TextBlock
Text="Templated Control"
DoubleTapped="InputElement_OnTapped"/>
<TextBox
KeyDown="InputElement_OnKeyDown"/>
</StackPanel>
</ControlTemplate>
</Setter>
</Style>
</Styles>
MyTmplatedControl.axaml.cs:
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace MyNamespace;
public class MyTemplatedControl : TemplatedControl
{
private void InputElement_OnTapped(object? sender, RoutedEventArgs e)
{
(sender as TextBlock).Text = "DOUBLE TAPPED";
}
private void InputElement_OnKeyDown(object? sender, KeyEventArgs e)
{
(sender as TextBox).Background = new SolidColorBrush(Colors.Green);
}
}
PS. As a beginner, I also don't know yet, how to access controls from .axaml.cs to .axaml, help me, if it is possible, but I think, this is a topic for another issue.

Related

How do I wrap a ContentDialog in a custom Control?

I'm trying to make a re-usable WinUI dialog to display progress information, but I want the fact that I'm using a ContentDialog to be an implementation detail and not expose its API. I figured I could do this by deriving from Control and creating a ContentDialog inside of its ControlTemplate.
Something like this:
[TemplatePart(Name = PART_Dialog, Type = typeof(ContentDialog))]
public class ProgressDialog : Control
{
private const string PART_Dialog = "PART_Dialog";
private ContentDialog _dialog;
public ProgressDialog()
{
DefaultStyleKey = typeof(ProgressDialog);
}
public async Task ShowAsync()
{
if (_dialog != null)
{
_ = await _dialog.ShowAsync(ContentDialogPlacement.Popup);
}
}
protected override void OnApplyTemplate()
{
_dialog = GetTemplateChild(PART_Dialog) as ContentDialog;
base.OnApplyTemplate();
}
}
With a style defined like so:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Controls">
<Style TargetType="local:ProgressDialog" BasedOn="{StaticResource DefaultProgressDialog}" />
<Style x:Key="DefaultProgressDialog" TargetType="local:ProgressDialog">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ProgressDialog">
<ContentDialog x:Name="PART_Dialog">
<Grid>
<TextBlock Text="Hello, world!" />
</Grid>
</ContentDialog>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And then I would show the dialog like a ContentDialog:
var dialog = new ProgressDialog();
dialog.XamlRoot = this.XamlRoot;
await dialog.ShowAsync();
I have the resource dictionary specified in Generic.xaml, but the control doesn't even attempt to load the template. My OnApplyTemplate method is never called, so _dialog doesn't get wired up. I assume this is because I'm not actually creating the control in the visual tree, but then how does ContentDialog do it?
If I call ApplyTemplate() myself in ShowAsync(), it returns false and the template still isn't loaded.
How do I wrap a ContentDialog in a custom Control?
Derive from this document
Run code that can only work once the XAML-defined visual tree from templates has been applied. For example, code that obtains references to named elements that came from a template, by calling GetTemplateChild, so that members of these parts can be referenced by other post-template runtime code.
If you just implement, but not add into visual tree. OnApplyTemplate will not be invoke, and GetTemplateChild will return null. please declare in the xaml like the following.
<Grid>
<Button Click="Button_Click" Content="Open" />
<local:ProgressDialog x:Name="Dialog" />
</Grid>
Or make a class that inherit ContentDialog directly, for more please refer this document.

Getting Error CS1061 on EventSetter of App.xaml

I'm trying to create an element by my code and associate a style for it, also associating its EventSetter, the style works perfectly but when I try to run the function it does not work.
App.xaml
<Application x:Class="Learning.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Learning">
<Application.Resources>
<Style TargetType="Label" x:Key="LabelTituloEstiloPadrao">
<Setter Property="Background" Value="White" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="40,20,0,0" />
<EventSetter Event="MouseLeftButtonUp" Handler="lbl_MouseLeftButtonUp"/>
<EventSetter Event="MouseRightButtonUp" Handler="lbl_MouseRightButtonUp"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
MainWindow.xaml.cs
public ViewConfigAgendaDin()
{
InitializeComponent();
ConfigInicial();
Label l = new Label();
lblTeste.Style = (Style)App.Current.Resources["LabelTituloEstiloPadrao"];
StackHorarios.Children.Add(l);
}
private void lbl_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Right");
}
public void lbl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Left");
}
when the application is being built, two errors are fired into the EventSetter
Error CS1061 "App" does not contain a setting for
"lbl_MouseLeftButtonUp" and could not find any "lbl_MouseLeftButtonUp"
extension method that accepts a first argument of type "App" (is there
a usage directive or assembly reference missing?)
The same error also happens for the right event, how can I do to implement these two methods in my class where I am using this without giving problems?
Generally, you get Error CS1061 when a method is inaccessible from XAML.
Most common cases are:
event handler is not declared in code-behind
XAML's x:Class tag not matching the actual name of the class
name of the method not matching the Handler of event setter
incorrect handler method signature
using a private method in the base class instead of protected
a need for restarting the visual studio in rare cases
Looking at the XAML code, your class name is Learning.App
<Application x:Class="Learning.App"
But the code behind in which the event handlers are declared is ViewConfigAgendaDin
public class ViewConfigAgendaDin
You can't put the event handlers anywhere and expect the compiler to find them by itself. Because the handler is used in App.XAML, you need to Move the event handlers to App.xaml.cs and it will be good to go.
If you need them to be in ViewConfigAgendaDin class, either define the Style in ViewConfigAgendaDin.xaml or call a method in ViewConfigAgendaDin.xaml.cs from App.xaml.cs
Edit:
For example:
ViewConfigAgendaDin.xaml:
<ViewConfigAgendaDin
xmlns:v="clr-namespace:MY_NAMESPACE">
...
<Label Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type v:ViewConfigAgendaDin}}}"
Style="{StaticResource LabelTituloEstiloPadrao}"/>
...
</ViewConfigAgendaDin>
ViewConfigAgendaDin.xaml.cs:
public void MyMethodForRightClick(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Right");
}
App.xaml.cs:
private void lbl_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
((sender as Label).Tag as ViewConfigAgendaDin).MyMethodForRightClick(sender, e);
}
Another way to handle this situation is to avoid code-behind altogether. Instead, make use of MVVM and Command Binding. You can easily bind any event to a command using Interactions

Visual Studio Designer shows empty Window when using custom ContentPropertyAttribute

My application has a lot of windows and most of them share some basic features. Because of that I extended the Window class to create a base for all my windows.
Everything compiles and displays fine but the designer just shows an empty window when I use my window class.
I made a basic example that can be easily used, my real window is much more complex but this shows the problem.
Here is the code:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
namespace WpfApplication1
{
[ContentProperty("ContentElement")]
public class MyWindow : Window
{
public ToolBar ToolBar { get; private set; }
public StatusBar StatusBar { get; private set; }
public Border ContentBorder { get; private set; }
public UIElement ContentElement
{
get { return (UIElement)GetValue(ContentElementProperty); }
set { SetValue(ContentElementProperty, value); }
}
public static readonly DependencyProperty ContentElementProperty = DependencyProperty.Register(
"ContentElement", typeof(UIElement), typeof(MyWindow),
new PropertyMetadata(null, (d, e) =>
{
MyWindow w = (MyWindow)d;
w.ContentBorder.Child = (UIElement)e.NewValue;
}));
public MyWindow() : base()
{
ToolBar = new ToolBar();
ToolBar.Height = 30;
ToolBar.VerticalAlignment = VerticalAlignment.Top;
StatusBar = new StatusBar();
StatusBar.Height = 20;
StatusBar.VerticalAlignment = VerticalAlignment.Bottom;
ContentBorder = new Border();
ContentBorder.SetValue(MarginProperty, new Thickness(0, 30, 0, 20));
Grid grid = new Grid();
grid.Children.Add(ToolBar);
grid.Children.Add(ContentBorder);
grid.Children.Add(StatusBar);
Content = grid;
}
}
}
XAML example for using MyWindow:
<local:MyWindow x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Grid>
<Rectangle Fill="Blue" />
</Grid>
</local:MyWindow>
Doing the exact same thing with a UserControl works just fine, also in the designer. Just replace every occurance of MyWindow with MyUserControl and extend from UserControl if you want to try that.
Is there any way I can get a custom Window like that to work with the designer, or do i have to make a UserControl and use that in every window?
Also, is this some kind of bug or intended behavior?
Addional info: I'm running Visual Studio 2015 Community and I'm using .net 4.6
I Also tried another approach. Instead of using the ContentPropertyAttribute i have overwritten the ContentProperty like this:
new public object Content {
get { return GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
new public static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(BaseUserControl), new PropertyMetadata(null, (s, e) =>
{
MyWindow bw = (MyWindow)s;
bw.ContentBorder.Child = (UIElement)e.NewValue;
}));
Again this works completely fine with a UserControl. With a Window I can at least see the Content in the designer now, but the ToolBar and StatusBar are still not showing up in the designer. When running it everything works correctly.
First, I am no super expert on WPF, but have done a bunch and think I can offer and help clarify some components. First, you can NOT derive from a .XAML based declaration of a WPF-Window, it can only be if entirely within code. I have come to find that sometimes the visual element building is much easier to do in XAML than it is within code, but both can and do work.
So, that said, I would like to offer a solution that might work for you. Starting with WPF Window Style / Templatea, if you are not already familiar with them, along with other controls you can run through their defaults.
First, I am starting with a RESOURCE DICTIONARY STYLE definition that will mimic much of what you may want in your default form. This becomes the stuff within the "ControlTemplate" of the style definition. I have created this as a file "MyWindowStyle.xaml" at the root level WpfApplication1 I created on my machine (just to match your sample project file namespace reference).
Inside the template, you could have almost anything... grids, dock panel, stack panels, etc. In this case, I have used a DockPanel and added your sample ToolBar, StatusBar and two extra labels just for sample. I also preset size and bogus color just to give visualization of the parts when you confirm their impact.
The CRITICAL element to look at is the . This identifies where the content for each of your DERIVED Windows content will be placed... Think of it as a place-holder for each one of your forms for individuality while the rest of the form, its controls all remain consistent. You will see it come into play as you play around with it.
The content of it is and notice the style x:Key="MyWindowStyle". This coincidentally is the same as the xaml, but you could have 100's of styles within a single resource dictionary. I am keeping simple to just the one for demo purposes.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Style x:Key="MyWindowStyle" TargetType="Window">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<Grid.Background>
<SolidColorBrush Color="{DynamicResource WindowColor}"/>
</Grid.Background>
<AdornerDecorator>
<DockPanel LastChildFill="True" Background="Blue">
<!-- List items docked to the top based on top-most first going down -->
<ToolBar x:Name="tmpToolBar" Height="45" DockPanel.Dock="Top" />
<Label Content="Testing by Style"
Height="30" Width="150" DockPanel.Dock="Top"/>
<!-- When docking to the bottom, start with bottom most working up -->
<StatusBar x:Name="tmpStatusBar" Height="30"
Background="Yellow" DockPanel.Dock="Bottom" />
<Label Content="Footer area based from style"
Height="30" Width="250" DockPanel.Dock="Bottom" />
<!-- This one, since docked last is rest of the space of the window -->
<ContentPresenter DockPanel.Dock="Bottom"/>
</DockPanel>
</AdornerDecorator>
<ResizeGrip x:Name="WindowResizeGrip"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Visibility="Collapsed"
IsTabStop="false" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ResizeMode" Value="CanResizeWithGrip">
<Setter TargetName="WindowResizeGrip"
Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Next, we need to make this publicly available for the entire duration of the application, including availability within the designer mode... Within your projects "App.xaml" which is the startup for the application, it will have a default and empty area. Replace it with this.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WpfApplication1;component/MyWindowStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now, to a CODE-ONLY (not a .xaml window based definition) of your "MyWindow.cs" class. If you look at the style where I declared the toolbar and statusbar, I assigned them the names of "tmpToolBar" and "tmpStatusBar" respectively. Notice the [TemplatePart()] declarations. I am now expecting the template to HAVE these controls by the given name within the TEMPLATE somewhere.
Within the constructor, I am loading the Style from the App.xaml resource dictionary being fully available. Then I follow-up with the OnApplyTemplate() which I typically heavily document my code so anyone following me has some idea how / where things originated from and self explanatory.
My entire "MyClass.cs" is below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace WpfApplication1
{
[TemplatePart(Name = "tmpToolBar", Type = typeof(ToolBar))]
[TemplatePart(Name = "tmpStatusBar", Type = typeof(StatusBar))]
public class MyWindow : Window
{
protected ToolBar myToolBar;
protected StatusBar myStatusBar;
public MyWindow() : base()
{
// NOW, look for the resource of "MyWindowStyle" within the dictionary
var tryStyle = FindResource("MyWindowStyle") as Style;
// if a valid find and it IS of type Style, set the style of
// the form to this pre-defined format and all it's content
if (tryStyle is Style)
Style = tryStyle;
}
// the actual template is not applied until some time after initialization.
// at that point, we can then look to grab object references to the controls
// you have need to "hook up" to.
public override void OnApplyTemplate()
{
// first allow default to happen
base.OnApplyTemplate();
// while we get the style loaded, we can now look at the expected template "parts"
// as declared at the top of this class. Specifically looking for the TEMPLATE
// declaration by the name "tmpToolBar" and "tmpStatusBar" respectively.
// get object pointer to the template as defined in the style template
// Now, store those object references into YOUR Window object reference of Toolbar
var myToolBar = Template.FindName("tmpToolBar", this) as ToolBar;
if (myToolBar != null)
// if you wanted to add your own hooks to the toolbar control
// that is declared in the template
myToolBar.PreviewMouseDoubleClick += myToolBar_PreviewMouseDoubleClick;
// get object pointer to the template as defined in the style template
var myStatusBar = Template.FindName("tmpStatusBar", this) as StatusBar;
if (myStatusBar != null)
myStatusBar.MouseDoubleClick += myStatusBar_MouseDoubleClick;
// Now, you can do whatever else you need with these controls downstream to the
// rest of your derived window controls
}
void myToolBar_PreviewMouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// in case you wanted to do something based on PreviewMouseDoubleClick of the toolbar
MessageBox.Show("ToolBar: Current Window Class: " + this.ToString());
}
void myStatusBar_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// in case something for MouseDoubleClick on the StatusBar
MessageBox.Show("StatusBar: Current Window Class: " + this.ToString());
}
}
}
So now, lets put it into place. Have your application's main window derive from the MyWindow class. The only thing you need there is
namespace WpfApplication1
{
public partial class MainWindow : MyWindow
{}
}
In the DESIGNER of your form, put in a few controls, such as label, textbox, whatever. You do not see your actual other style yet, but just go with it. Save and run the sample app. Your main window should be displayed with the entire pre-defined template there ALONG WITH the few extra control you had placed specifically on this form.
Now, to get the full visualization in your "MainWindow" from the designer perspective. Within the .xaml area of
<my:MyWindow
x:Class="WpfApplication1.MainWindow"
[other declarations] >
just add the following before the close ">"
Style="{StaticResource MyWindowStyle}"
The resource is available via the App.xaml at startup and you should now be able to see the entire visual while you are designing... but you cant change the outermost template, just the content specific to this one page as mentioned about the "ContentPresenter" part of the template definition. What you are changing is within the place-holder portion allocated by the Template. If you want to change the main part of the window controls, you need to update the TEMPLATE!
But here is part of the trick of the template designer. Start with this, and build in what you need visually, get it placed right and once ready, take it out of here and put into the template and now it is applicable to the rest of all windows. Fix fonts, sizes, colors, whatever.
Hope this helps, and if you have any questions for follow-up, let me know.
Window class is very complex in compare to UserControl class. Microsoft has written more than 8k lines of code in Window class compare to 80 lines in UserControl, additionally Window class contain many operation/event/restriction on content property, and any one piece of code is hindering in rendering the content when you use [ContentProperty("ContentElement")] with the Window subclass MyWindow .
Probably making it a UserControl is better option, If not possible you can write some code temporarily(copy code from ContentElement property) in content property to see the design view.
<lib:MyWindow.Content>
<Button Content="Click" Width="200" />
</lib:MyWindow.Content>
and then just remove the code before run time. (Not a good idea but, whatever works.:) and I suspect that you have already figured that out.

How to make a cell in a DATAGRID link to another Window?

I get data from an SQL database into my DATAGRID on my WPF application. I want to be able to click a cell that is named : 'Left to audit' and from there get redirected to anothter page with all the information on how many is left to audit.
How do i go about creating the click event to take me to another page?
P.S. I am a Novice.
Edit: http://i.stack.imgur.com/LGnHA.png
Edit: http://i.stack.imgur.com/tU0bA.png - Want to click in the cells on the last column.
Hope this work:
<DataGridHyperlinkColumn Binding="{Binding Link}">
<DataGridHyperlinkColumn.ElementStyle>
<Style>
<EventSetter Event="Hyperlink.Click" Handler="DG_Hyperlink_Click"/>
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
private void DG_Hyperlink_Click(object sender, RoutedEventArgs e)
{
Hyperlink link = (Hyperlink)e.OriginalSource;
Process.Start(link.NavigateUri.AbsoluteUri);
}
If the URI points a website it will be opened with the default web-browser, if it is a folder it will be opened in explorer, if it is a file it will be opened with the default application associated with it.
To use this for autogenerated columns your property needs to be of type Uri so a DataGridHyperlinkColumn is generated. You then can hook up the event by placing the style in the DataGrid.Resources:
<DataGrid.Resources>
<Style TargetType="Hyperlink">
<EventSetter Event="Click" Handler="DG_Hyperlink_Click"/>
</Style>
</DataGrid.Resources>
Try This..
Add an EventSetter on the CellStyle:
<DataGrid.CellStyle>
<Style>
<EventSetter Event="DataGridCell.MouseLeftButtonDown"
Handler="CellClicked" />
</Style>
</DataGrid.CellStyle>
In Code Behind add Handler:
private void CellClicked(object sender, MouseButtonEventArgs e)
{
String cellContent = ((TextBlock)sender).Text;
xamlAllocateAudit window = new xamlAllocateAudit
{
DataContext = cellContent
}
window.Show();
}
Works on my end.. First click selects cell, second click fires handler, which opens the new window.
if you want the same window to be updated, then keep a reference of the window, if existing, update it's datacontext.
On the ohter side in the xamlAllocateAudit, create handler for the event "DataContextChanged":
<Window x:Class="WpfApplication3.xamlAllocateAudit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DetailsWindow" Height="300" Width="300"
DataContextChanged="Window_DataContextChanged">
<!-- Some graphics -->
</Window>
And in CodeBehind:
private void Window_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var newDataContext = e.NewValue;
//do stuff with DataContext
}
Cheers!!

Is it possible to dynamically add events to buttons in XAML?

I am new to WPF/XAML so please bear with the noob question.
I have designed a control panel that will eventually function as a backend for my website, and have just finished laying out all the buttons in tabs using TabControl element. (this is designed using the Visual Studio 'Window' forms.
My question is, is it possible to create a function in the xaml.cs file that will dynamically handle a specific event for all my button elements ? for example...
I have 30+ buttons and dont want 30 different Click="btnCustomers_click" + their respective functions in the c# code. What I desire is say one function that would allow me to click any button and then open a new window depending on which button was selected.
The below code is my current design however for 30+ buttons their will be alot of functions and it will be messy, hence my desire to have one function control which window is opened depending on which button is clicked.
private void btnMerchants_click(object sender, RoutedEventArgs e)
{
var newWindow = new frmMerchants();
newWindow.Show();
}
Thanks in advance for any advice given!! :)
You could use a style for this:
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="btnMerchants_click"/>
</Style>
If you set this up in the resources somewhere without an x:Key it will apply to all buttons.
e.g. if you have a Grid and you want a certain style to apply to all Buttons in it you would define it like this:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Grid.Resources>
<Grid.Children>
<!-- Buttons and stuff -->
</Grid.Children>
</Grid>
If you just want to apply it to some buttons set the x:Key and reference the style:
<Grid>
<Grid.Resources>
<Style x:Key="AttachClickHandlerStyle" TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Grid.Resources>
<Grid.Children>
<Button Content="Click me!" Style="{StaticResource AttachClickHandlerStyle}"/>
<Button Content="Click me, too!" Style="{StaticResource AttachClickHandlerStyle}"/>
<Button Content="Something different." Click="SomeOtherButton_Click"/>
</Grid.Children>
</Grid>
In general you should refactor any attributes that occur more than once into a style to prevent duplicate code.
Also, since you are a beginner the following articles might be of interest:
Styling and Templating
Resources Overview
You can use routed events on the parent container.
Example:
<Grid Button.Click="GeneralHandler">
<!-- Some stuff -->
</Grid>
In the code behind:
public void GeneralHandler(object sender, RoutedEventArgs e)
{
Button b = e.OriginalSource as Button;
//<-- Do something
}
You can read more about it on MSDN.
Just assign the exact same Click="btnCustomers_click" handler (with a general function name) to all the buttons. Then in the function open the correct window based on the sender's Name.

Categories