Can't access ItemInvoked event handler of WindowsXamlHost control - c#

I use xamlIslands to host a custom UWP control in a WPF, .NetCore3 project. I followed instructions from this MSDN article in order to use UWP controls in WPF - Host a custom UWP control in a WPF app using XAML Islands
Other articles mention that the WindowsXamlHost's ChildChanged event handler is used to access the underlying UWP control's properties, handle events etc. Therefore, I am trying to access the ItemInvoked handler within the WPF project's window.xaml.cs file
I tried the linked article above's code. ItemInvoked it not listed by the dropdown as a choosable event for userControl below:
private void WindowsXamlHost_ChildChanged(object sender, EventArgs e)
{
WindowsXamlHost windowsXamlHost = sender as WindowsXamlHost;
global::MyUWPApp.CustomControls.myNavigationView userControl =
windowsXamlHost.GetUwpInternalObject() as global::MyUWPApp.CustomControls.myNavigationView;
}
Another Approach which does give ItemInvoked as optional event handler:
private void WindowsXamlHost_ChildChanged(object sender, EventArgs e)
{
var host = (WindowsXamlHost)sender;
var myNavView = host.Child as Windows.UI.Xaml.Controls.NavigationView;
myNavView.ItemInvoked += MyNavView_ItemInvoked; ;
}
private void MyNavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
throw new NotImplementedException();
}
Building that breaks on myNavView.ItemInvoked += MyNavView_ItemInvoked; with error System.ArgumentException: 'Delegate to an instance method cannot have null 'this'.
Hovering with mouse on myNavView within the code above gives info: (local variable) NavigationView myNavView
I guess that does not work because it is not an instance of the object.
General info:
The custom control is "hosted" in a UWP project, which is linked to the WPF project. As according to the article mentioned above. Within the WPF project window where I want to use the custom control, the following event handlers are accessible which seem relevant or possibly useful, in window.xaml:
<xaml:WindowsXamlHost InitialTypeName="MyUWPApp.CustomControls.myNavigationView"
ChildChanged="WindowsXamlHost_ChildChanged"
Loaded="WindowsXamlHost_Loaded_1"
Initialized="WindowsXamlHost_Initialized"
/>
I want to be able to access ItemInvoked event handler to properly manage selections in a UWP NavigationView, as according to this MSDN article: Using the NavigationView in your UWP applications

Related

ContextMenu.SourceControl property doesn't exists

I am making a WPF .NET 4.8 Exe application.I placed an TreeView control and made a void that is firing when window is loaded.This void adds all the sub directories and all of the files in all the sub directories and adds them to TreeView as TreeViewItem, and when they are creating their ContextMenu property is binding to a premade ContextMenu control.It also binds a click event to the MenuItems that ones ContextMenu contains.
I scripted the click event's void as RoutedEventArgs and wrote the code below (tried to access the TreeViewItem i created before).
I made some changes in my code to fix that problem but it did not work.
The code before:
void showInExplorerFolder_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("event triggered");
MenuItem menuItem = (MenuItem)sender;
//string tag = menuItem.Tag.ToString();
ContextMenu parent = (ContextMenu)menuItem.Parent;
var baseParent = parent.SourceControl;
Console.WriteLine("got success parent; ; ; ; ; ;" + menuItem.Name);
}
The code after:
void showInExplorerFolder_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("event triggered");
MenuItem menuItem = (MenuItem)sender;
//string tag = menuItem.Tag.ToString();
ContextMenu parent = (ContextMenu)menuItem.Parent;
TreeViewItem baseParent = (TreeViewItem)parent.SourceControl;
Console.WriteLine("got success parent; ; ; ; ; ;" + menuItem.Name);
}
And after theese changes i could not find any solution.
And the error code is here:
CS1061 'ContextMenu' does not contain a definition of 'SourceControl' and no inaccessible extension method 'SourceControl' is available that accepts a first argument of type 'ContextMenu' (maybe you are missing a usage or annotation reference?)
I could not find any solution.If anyone could help me, i will be thankful.
What you have done here is mixed WinForms code sample with WPF application.
To solve your problem you need to change
(TreeViewItem)parent.SourceControl; which is WinForms as SourceControl is part of ControlMenuStrip which lives in System.Windows.Forms.dll MSDN link, this is very important as WPF doesn't use that dll. It is a separate technology which uses different operating system components to render UI. For example WinForms is using GDI+ where WPF uses DirectX to render onto screen. Because of that you can't mix the 2 together as they are fundamentally different.
Solution
Use this ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as it is using WPF Controls and it is the equivalent of SourceControl. Here is a link to MSDN that will show you, it is in a different assembly.
Hope this helps

Can I "click" a WinUI 3 Button from code?

I would like to programmatically cause a Click event to fire for a Button in a WinUI 3 desktop app. I've seen lots of questions about how to deal with this on SO but the answers all involve invoking the handler (using commands or direct calls, etc.), instead of through firing the event on the Button.
This is a great choice if you actually have access to the handler, but what if you don't? What if the Button is embedded in a more complex control and the handler is internal and does some non-trivial (or unknown) additional processing?
For example, I recently tried to reformat the DatePicker control (which seems to have a mind of its own about size and placement of its constituent TextBlocks and LoopingSelectors). I tried rewriting Styles and deriving Controls, worked with MeasureOverride and ArrangeOverride - all the common approaches - but nothing worked. DatePicker clearly does formatting in code. I finally just hid the Button (FlyoutButton) DatePicker defines and added my own. But now I'd like my Button (ReplacementFlyoutButton) to invoke the same handler the original FlyoutButton did, thus creating the proper Flyout and doing all the date localization, etc. for me. Overriding OnApplyTemplate in a derived class gives me access to the underlying FlyoutButton (in DatePicker):
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Tree looks like:
// this as DatePicker
// LayoutRoot as Grid
// HeaderContentPresenter as ContentPresenter
// FlyoutButton as Button
// FlyoutButtonGrid as Grid
// ContentPresenter as ContentPresenter
// FlyoutButtonContentGrid as Grid
// DayTextBlock as TextBlock
// MonthTextBlock as TextBlock
// YearTextBlock as TextBlock
// FirstPickerSpacing as Rectangle
// SecondPickerSpacing as Rectangle
DayTextBlock = GetTemplateChild("DayTextBlock") as TextBlock;
MonthTextBlock = GetTemplateChild("MonthTextBlock") as TextBlock;
YearTextBlock = GetTemplateChild("YearTextBlock") as TextBlock;
FirstPickerSpacing = GetTemplateChild("FirstPickerSpacing") as Rectangle;
SecondPickerSpacing = GetTemplateChild("SecondPickerSpacing") as Rectangle;
FlyoutButtonContentGrid = GetTemplateChild("FlyoutButtonContentGrid") as Grid;
FlyoutButton = GetTemplateChild("FlyoutButton") as Button;
_replacementFlyoutButton = GetTemplateChild("ReplacementFlyoutButton") as Button;
if (_replacementFlyoutButton is not null) { _replacementFlyoutButton.Click += OnReplacementFlyoutButtonClick;}
}
Is there any way to invoke the Click event on DatePicker or its FlyoutButton in OnReplacementFlyoutButtonClick()?
Thanks for any ideas.
(Just as a note, neither the DatePicker nor the FlyoutButton have a non-null ContextFlyout and FlyoutButton's Flyout is null.)
All credit goes to #SimonMourier who pointed out that Microsoft UI Automation makes this easy - thank you Simon.
I was unable to find a good, well structured introduction to the use of UI Automation in WinUI 3 but, after looking over the documentation for the Microsoft.UI.Xaml.Automation.*, and particularly Microsoft.UI.Xaml.Automation.Peers, namespaces I realized that WinUI 3 Controls already implement classes that expose them to Microsoft UI Automation. For my question, the relevant class is Microsoft.UI.Xaml.Automation.Peers.ButtonAutomationPeer (please note the namespace for WinUI 3).
The modified code:
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_replacementFlyoutButton = GetTemplateChild("ReplacementFlyoutButton") as Button
?? throw new ArgumentException("Missing ReplacementFlyoutButton in DatePickerEx");
var FlyoutButton = GetTemplateChild("FlyoutButton") as Button
?? throw new ArgumentException("Missing FlyoutButton in DatePickerEx");
_replacementButtonAutomationPeer = FrameworkElementAutomationPeer.FromElement(FlyoutButton) as ButtonAutomationPeer
?? throw new ArgumentException("Missing ButtonAutomationPeer in DatePickerEx");
_replacementFlyoutButton.Click += OnReplacementFlyoutButtonClick;
}
private void OnReplacementFlyoutButtonClick(object sender, RoutedEventArgs e)
=> _replacementButtonAutomationPeer.Invoke();
Clicking the ReplacementFlyoutButton will now Invoke the FlyoutButton in the OnReplacementFlyoutButtonClick event handler, as required.

Windows Forms - using public event to subscribe Form to a user control event

I have an issue when it comes working with events and/or delegates. I saw very similar questions but still the real implementation is not clear to me. So please when you answer be more specific so I can try and eventually understand how exactly creating/handling of public/custom events work by doing it in a code I know.
What I have is a User Control which is simply a text box and a button I need to change a record in a database using the value from the text box. I'm using this control for many forms so I need to know which entity exactly I'm using and be able to call it's own save method. Doing all that will be easier if I just can use the click event of the button from my User Control and then call the Save() method of the current form.
This is my User Control :
namespace UserControls.CommonControls
{
public delegate void ClickMe(string message);
public partial class ChangeCode : UserControl
{
public event ClickMe CustomControlClickMe;
public ChangeCode()
{
InitializeComponent();
}
private void btnChange_Click(object sender, EventArgs e)
{
if (CustomControlClickMe != null)
CustomControlClickMe("Hello");
//ToDo fill
//MessageBox.Show("To Do: Write the busieness logic.");
}
public void SetTextBoxMask(MaskedTextBox txtBox)
{
txtChange.Mask = txtBox.Mask;
}
}
}
I post it with the last attempt I made to try and implement what I need.
This is one of the form that need to use the Click event from the User Control and more specific the Constructor because if I understand right there is the place where I have to subscribe for the event :
public MaterialEdit()
{
InitializeComponent();
UserControls.CommonControls.ChangeCode. += new ClickMe(button2_Click);
}
UserControls.CommonControls.ChangeCode - this is how I reach my User Control it's named ChangeCode.
From what you pasted it is not clear that you added ChangeCode control to your form. To use the control and it's events and properties, first you must create new instance to it and add it to the form. This is done:
In designer, by dragging control from Toolbox to the form
In code editor, by invoking control constructor and adding new object to control collection
Only then can you handle event of that object. Let's say that you dropped ChangeCode control to a form, and that Visual Studio named it ChangeCode1. You attach a handled to CustomControlClickMe event like this:
ChangeCode1.CustomControlClickMe += new ClickMe(button2_Click);
Code you pasted (UserControls.CommonControls.ChangeCode. += new ClickMe(button2_Click);) is incorrect for several reasons:
Syntactically, left hand side expression ends with . which makes it incorrect assignment target (UserControls.CommonControls.ChangeCode.)
Event name is not provided, only the control name (you need to end left hand side of assignment with what you want to assign to - .CustomControlClickMe)
You are trying to attach handler to a class and not an object

How to get the Custom Task Pane Object on the Ribbon control Class

Developing a Excel vsto project, how could I handle the Custom Task Pane in the Class which is a Ribbon Control.
For example, I would like to show the Custom Task Pane when I click the button of the Ribbon Control.
Dora
I assume you are working with an Excel VSTO add-in, with the Ribbon Visual Designer. You can achieve what you want by making your custom Task Pane accessible via a property on your Add-In:
public partial class ThisAddIn
{
private CustomTaskPane taskPane;
internal CustomTaskPane TaskPane
{
get
{
return this.taskPane;
}
}
... and adding a button in your Ribbon, and adding an event handler for the click event, accessing the add-in via Globals:
private void MyRibbonButton_Click(object sender, RibbonControlEventArgs e)
{
Globals.ThisAddIn.TaskPane.Visible = true;
}
I wrote a post a while back which describes the process, you may find it useful.
This is also feasible using the xml ribbon.
This can be accomplished by having a Win Forms user control.
I've worked on a project where we had to extend MS Word and needed this functionality, but the same example will apply to Excel.
Another interesting way I stumbled upon on the net is to have a Windows user control and host a WPF user control within the Windows control!
This ofcourse allows you to take advantage of all the awesome tools you get with WPF, here is an example:
1)Drop a ToggleButton on a Ribbon(Visual Designer).This will be used to show hide the task pane.
Using ToggleButton is a good choice as it appears highlighted when pressed down.
2)Add below code to the click event of the ToggleButton
Globals.ThisAddIn.TaskPane.Visible = ((RibbonToggleButton)sender).Checked;
3)Add a reference from your project to the following assembly - WindowsFormsIntegration
4)In your ThisAddIn.cs add the two using directives listed below:
using Microsoft.Office.Tools;
using System.Windows.Forms.Integration;
5)Add two user controls
5.1)User control (name - taskPaneControl1)
5.2)User control(WPF),(name - con)
Using the names I've used will help when copying/pasting the code below but by any means change it if you wish to
6)Add below code to the ThisAddIn.cs class
public CustomTaskPane TaskPane
{
get{return taskPaneValue;}
}
private TaskPaneControl taskPaneControl1;
private CustomTaskPane taskPaneValue;
private WpfControl con;
internal void AddTaskPane()
{
ElementHost host = new ElementHost();
con = new WpfControl();
host.Child = con;
host.Dock = DockStyle.Fill;
taskPaneControl1 = new TaskPaneControl();
taskPaneControl1.Controls.Add(host);
taskPaneValue = this.CustomTaskPanes.Add(taskPaneControl1, "My Taskpane");
taskPaneValue.Visible = true;
}
6)Add the two code below to the Startup event in your ThisAddIn.cs
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
AddTaskPane();
taskPaneValue.Visible = false;
}
When an MS Office Application is opened the task pane will be hidden toggle the Visible property to change this in the Startup event.
Navigate to the ToggleButton and press it a few times to make sure the task pane is showing as expected
Also have a look at the following link most of my code came from here - http://xamlcoder.com/cs/blogs/joe/archive/2007/07/17/using-wpf-with-vsto-office-2007.aspx
This is a difficult challenge since the Ribbon and Task Panes are separate entities. One of the main challenges is that there is only one instance of the Ribbon class and multiple instances of the task pane for each inspector. To this properly requires some advanced understanding of the Office internals.
The solution also depends on whether you are using the Ribbon XML or Ribbon Designer. Which approach are you using?

How to open a window then load my XAML file to it? (XAML and C#)

I am new to WPF and C# and i need some help - sorry about the newbie question!
Anyway I have a control panel 'window' as the file thats loaded when i run my project, and i then have a button on this control panel, that when clicked triggers an event. Inside this 'event function' I am trying to load a new window that has its own XAML code behind, how do i go about doing this? I have googled but to no avail.
Please explain in laymens terms, I am still getting the hang of this all.
Thanks!
private void btnCustomers_clicked(object sender, RoutedEventArgs e)
{
//load in Customers.xaml file here - in a new window
}
You need to declare an instance of the class that is your other window then call Show() on it. So if your other window is call MySecondWindow you write the following in your event handler.
MySecondWindow otherWindow = new MySecondWindow();
otherWindow.Show();
A basic explination of how windows work can be found on the MSDN Site.

Categories

Resources