Getting Error CS1061 on EventSetter of App.xaml - c#

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

Related

How to add event to control inside TemplatedControl

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.

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.

How does the Style.BasedOn Property work internally?

Background
I am developing an application that generates Labels based on data provided in a CSV file. I would like the user to be able to apply Templates to change the appearance of these Labels, I also need the user to be able to Edit and Modify these Templates.
I am deriving these Templates from the Existing Style Class in WPF. Even though I am presenting this to the End user as a 'Template', for the sake of this post, I will refer to them as Styles to avoid confusion with Data Templating.
Due to a Style becoming Sealed after use or after being referenced by another style.BasedOn Property, in order to allow the user to Modify these Styles, for each modification, I need to generate a new Style based on the Current Style. I do this using the BasedOn Property.
Question
What is actually happening internally when the Style.BasedOn property is set and that style is consumed by an element?
My first thought was that a copy of the Setters collection was created and applied to the new Style, but as the following code shows, that is not the case:
var styleA = new Style();
styleA.Setters.Add(new Setter(/* DP and Value */));
var styleB = new Style();
styleB.BasedOn = styleA;
Console.WriteLine(styleA.Setters.Count);
Console.WriteLine(styleB.Setters.Count);
// Ouput.
// 1
// 0
My next thought is that the BasedOn property holds a reference to the style applied to it, and the actual logic is performed by the FrameworkElement.Style OnPropertyChanged handler. I had a look through the Reference Source, but in all honesty, got in over my head pretty quickly.
Any help or suggestions for another way to approach the problem will be greatly appreciated.
As you suggested for another approach, here is one commonly used: resource dictionnaries.
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="DefaultLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="20" />
</Style>
</ResourceDictionary>
StyleBlue.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style BasedOn="{StaticResource DefaultLabelStyle}" TargetType="Label">
<Setter Property="Background" Value="Blue" />
</Style>
</ResourceDictionary>
StyleRed.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style BasedOn="{StaticResource DefaultLabelStyle}" TargetType="Label">
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
Demo
using System;
using System.Windows;
namespace WpfApplication3
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
private void SetTheme(string theme)
{
var mergedDictionaries = Resources.MergedDictionaries;
mergedDictionaries.Clear();
var dictionary = new ResourceDictionary {Source = new Uri(theme)};
mergedDictionaries.Add(dictionary);
}
private void ButtonRedTheme_Click(object sender, RoutedEventArgs e)
{
SetTheme(#"pack://application:,,,/Themes/StyleRed.xaml");
}
private void ButtonBlueTheme_Click(object sender, RoutedEventArgs e)
{
SetTheme(#"pack://application:,,,/Themes/StyleBlue.xaml");
}
}
}
As you can see in Style.BasedOn, there's simply no indication of what's happening under the hood, certainly a lot.
However, following is said : Typically, you use the Markup Extensions and WPF
XAML to refer to an existing style.
As an end-user it happens that you simply don't have to know the inner workings as there are simpler patterns for using this feature : XAML / resource dictionaries.
There is plenty of documentation for styling/templates, start by reading this one : Styling and Templating
For your users you could direct them to XamlPad for creating these templates, you'd get real-time preview at the same time.
versed users will know what to do and will be able to
for beginners you can provide a starter pack of templates
Weigh the 'pros' and 'cons' of this solution against using 'CSV' and 'code' approach (extensible only with your involvement and IMO doomed to fail).
EDIT
You can see exactly what's happening in BasedOn by looking at the source code : http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Style.cs,dd312833d0723042

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!!

Propagate an event from style to MainWindow in WPF

I have a custom style in a separate XAML CustomTabItem.xaml which raises an event like:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="myProject.CustomTabItem">
...
...
<MenuItem Header="One">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<EventSetter Event="Click" Handler="ClickNewSpaceOne"/>
</Style>
</MenuItem.Style>
</MenuItem>
...
...
</ResourceDictionary>
And this easily raises an event in a file I created called CustomTabItem.xaml.cs:
namespace myProject
{
partial class CustomTabItem
{
private void ClickNewSpaceOne(object sender, RoutedEventArgs e)
{
//do stuff here
}
}
}
This all works fine, but I now need to raise an event in the MainWindow (of course in the event handler ClickNewSpaceOne) but I cannot figure out how to propagate this event to the MainWindow.
I found this article but it doesn't really look like the same situation, so any different article that I didn't find or any answer I would really appreciate.
The practice of using EventSetter in this case, not the best. And here's why:
He is bound to the BAML file that and should be event handler
Because it, is limited to the global function of the event, he just looking event handler in xaml.cs file. Also, because of this, from MSDN:
Event setters cannot be used in a style that is contained in a theme resource dictionary.
EventSetter can not be set in the Trigger
Quote from link:
Because using EventSetter to wire up event handler is a compile-time feature which is plumbed through IStyleConnector interface, there is another interface called IComponentConnector which is used by the XAML compiler to wire up event handler for standalone XAML elements.
What alternatives?
1 - Attached dependency property
Use the attached dependency property and its UIPropertyMetadata, you implement the necessary logic. For example:
// GetValue
// SetValue
public static readonly DependencyProperty SampleProperty =
DependencyProperty.RegisterAttached("Sample",
typeof(bool),
typeof(SampleClass),
new UIPropertyMetadata(false, OnSample));
private static void OnSample(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool && ((bool)e.NewValue) == true)
{
// do something...
}
}
More information can be found here:
How to inherit Button behaviour in WPF style?
Quit application from a user Control
How to clear the contents of a PasswordBox when login fails without databinding?
2 - Commands
Command in the WPF is a very powerful. Quote from MSDN:
The first purpose is to separate the semantics and the object that invokes a command from the logic that executes the command. This allows for multiple and disparate sources to invoke the same command logic, and it allows the command logic to be customized for different targets.
In this case, they can and should be used in Styles, Templates, DataTemplates. In style, you can set a command like this:
<Setter Property="Command"
Value="{Binding DataContext.YourCommand,
RelativeSource={Relative Source AncestorType={x:Type Control}}}">
Also, if you want to reference the command, you can declare the command as a static property then you can use Static extention to reference it.
3 - Using EventTrigger with Interactivity
In this case, the command is called by the EventTrigger. For example:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter" >
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
More information, can be founded here:
Using EventTrigger in XAML for MVVM
Binding WPF events to MVVM Viewmodel commands

Categories