How to fill ContextMenuStrip in XAML? - c#

I've created WPF application with NotifyIcon to work in tray.
public partial class MainWindow : Window
{
public NotifyIcon NotifyIcon { get; } = new NotifyIcon
{
Icon = Properties.Resources.status_on_ico,
Visible = true
};
public MainWindow()
{
InitializeComponent();
NotifyIcon.ContextMenuStrip = MyContextMenuStrip;
NotifyIcon.Click += NotifyIcon_Click;
}
private void Window_Closing(object sender, CancelEventArgs e)
{
e.Cancel = true;
WindowState = WindowState.Minimized;
}
private void NotifyIcon_Click(object sender, EventArgs e)
{
Show();
}
}
XAML of main window is nothing special and not relevant.
I want to create ContextMenuStrip of NotifyIcon in XAML (I know how to do it code behind but don't want it).
Here is what I've managed.
<WindowsFormsHost>
<wf:ContextMenuStrip x:Name="MyContextMenuStrip" TopLevel="False">
<wf:ContextMenuStrip.Items>
<!-- How to add items here? -->
</wf:ContextMenuStrip.Items>
</wf:ContextMenuStrip>
</WindowsFormsHost>
The question is how to add items to ContextMenuStrip.Items with Name and Click event handlers in XAML?

The question is how to add items to ContextMenuStrip.Items with Name and Click event handlers in XAML?
Try this:
<WindowsFormsHost>
<wf:ContextMenuStrip x:Name="MyContextMenuStrip" TopLevel="False">
<wf:ContextMenuStrip.Items>
<wf:ToolStripMenuItem Text="test1" Click="It_Click" />
<wf:ToolStripMenuItem Text="test2" />
</wf:ContextMenuStrip.Items>
</wf:ContextMenuStrip>
</WindowsFormsHost>
private void It_Click(object sender, EventArgs e)
{
MessageBox.Show("click!");
}

Related

How can I change a "Frame Content" in another class? (C# WPF XAML)

once to explain, I open a xaml page via "frame.content" and in this page I have opened, I want to open another one but on the frame where the second page is running.
but i can't open the page,
nothing happens. not even an expection.
So here what I have written:
This is the class from the page that is open
private void bttn_start(object sender, RoutedEventArgs e)
{
MainWindow mw = new MainWindow();
mw.JoinNextPage();
}
This is the MainWindow class where the frame is.
public partial class MainWindow : Window
{
public void JoinNextPage() => pageMirror.Content = new page_finish();
}
You should use RoutedCommand to trigger the Frame navigation instead of the static MainWindow reference.
This removes the complete navigation logic (button event handlers) from your pages.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static RoutedCommand NextPageCommand { get; } = new RoutedCommand("NextPageCommand", typeof(MainWindow));
public MainWindow()
{
InitializeComponent();
CommandBindings.Add(
new CommandBinding(NextPageCommand, ExecuteNextPageCommand, CanExecuteNextPageCommand));
}
private void CanExecuteNextPageCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ExecuteNextPageCommand(object sender, ExecutedRoutedEventArgs e)
{
// Logic to select the next Frame content
JoinNextPage();
}
}
MainWindow.xaml
<Window>
<Frame>
<Frame.Content>
<Page>
<Button Command="{x:Static local:MainWindow.NextPageCommand}"
Content="Next Page" />
</Page>
</Frame.Content>
</Frame>
</Window>
Try this:
private void bttn_start(object sender, RoutedEventArgs e)
{
MainWindow mw = (MainWindow)Application.Current.MainWindow;
mw.JoinNextPage();
}

WPF FlowDocumentScrollViewer automatically scroll to bottom of the document

I have a UserControl that the XAML looks like:
<Grid>
<FlowDocumentScrollViewer Name="ProvisionStatusMonitor" Document="{Binding Document}" SourceUpdated="OnSourceUpdated"/>
</Grid>
The code-behind looks like
private void OnSourceUpdated(object sender, DataTransferEventArgs e)
{
FlowDocumentScrollViewer docViewer = (FlowDocumentScrollViewer) sender;
var scrollViewer = (ScrollViewer)docViewer.Template
.FindName("ProvisionStatusMonitor", docViewer);
scrollViewer.ScrollToEnd();
}
But this doesn't seem to work. When the document is changed I was thinking that this event should fire and I could automatically scroll to the bottom of the document. What am I missing?
You may attach a PropertyChanged event handler to the view model in a DataContextChanged handler in the view.
Assuming that StatusView is a UserControl that contains the FlowDocumentScrollViewer shown in the question, it could look like this:
public StatusView()
{
InitializeComponent();
DataContextChanged += StatusViewDataContextChanged;
}
private void StatusViewDataContextChanged(
object sender, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is INotifyPropertyChanged oldViewModel)
{
oldViewModel.PropertyChanged -= ViewModelPropertyChanged;
}
if (e.NewValue is INotifyPropertyChanged newViewModel)
{
newViewModel.PropertyChanged += ViewModelPropertyChanged;
}
}
private void ViewModelPropertyChanged(
object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Document")
{
var docViewer = ProvisionStatusMonitor;
var scrollViewer = (ScrollViewer)docViewer.Template
.FindName("PART_ContentHost", docViewer);
scrollViewer.ScrollToEnd();
}
}

How to transfer control from one control to another

I created next WPF controls : Window1, View, Edit in different files:
In MainWindow.xaml MainWindow contein two ContentControls
<Grid>
<ContentControl x:Name="Viewer" Content="ContentControl1" DockPanel.Dock="Top" Height="Auto" RenderTransformOrigin="0.5,0.5">
</ContentControl>
<ContentControl x:Name="Editor" Content="ContentControl2" DockPanel.Dock="Top" Height="Auto" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5" Visibility="Hidden"/>
</Grid>
This is part of .cs file:
public partial class MainWindow : Window
{
View v = new View();
Edit e = new Edit();
public MainWindow()
{
InitializeComponent();
Window1.Viewer.Content = v;
Window1.Editor.Content = e;
}
public void swichToEditor()
{
Window1.Editor.Visibility = System.Windows.Visibility.Visible;
Window1.Viewer.Visibility = System.Windows.Visibility.Hidden;
}
public void swichToViewer()
{
Window1.Ediort.Visibility = System.Windows.Visibility.Hidden;
Window1.Viewer.Visibility = System.Windows.Visibility.Visible;
}
}
ComtentControl1 with x:name=Editor contain this userControl:
public partial class Edit : UserControl
{
public Edit()
{
this.InitializeComponent();
}
private void Button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
}
}
ComtentControl2 with x:name=Viewer contain this userControl:
public partial class View : UserControl
{
public View()
{
this.InitializeComponent();
}
private void Button2_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
}
}
When button1 will be pressed i need that Editor will be hide and Viewer will be visible. and vice-versa
I know better c++ syntax. and signal-slot method closer to me :)
What your advice to me?
You can use the RoutedEvent's behavior. You just need to register your Window to the Click RoutedEvent. Take a look:
public partial class MainWindow : Window
{
View v = new View();
Edit e = new Edit();
public MainWindow()
{
InitializeComponent();
Window1.Viewer.Content = v;
Window1.Editor.Content = e;
EventManager.RegisterClassHandler(GetType(), Button.ClickEvent, new RoutedEventHandler(OnButtonClick));
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (e.Source is View)
{
SwichToEditor();
}
else
{
SwichToViewer();
}
}
public void SwichToEditor()
{
Window1.Editor.Visibility = System.Windows.Visibility.Visible;
Window1.Viewer.Visibility = System.Windows.Visibility.Hidden;
}
public void SwichToViewer()
{
Window1.Ediort.Visibility = System.Windows.Visibility.Hidden;
Window1.Viewer.Visibility = System.Windows.Visibility.Visible;
}
}
Then you do not need to have a button click event handler in your UserControls.
I hope this sample can help you.

Close Window without code-behind in WPF

Is it possible to bind a Button to Close the Window without adding a code-behind event?
<Button Content="OK" Command="{Binding CloseWithSomeKindOfTrick}" />
Instead of the following XAML:
<Button Content="OK" Margin="0,8,0,0" Click="Button_Click">
With the code-behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
Close();
}
Thanks!
If you want close the dialog Window, you can add for Button IsCancel property:
<Button Name="CloseButton"
IsCancel="True" ... />
This means the following MSDN:
When you set the IsCancel property of a Button to true, you create a Button that is registered with the AccessKeyManager. The button is then activated when a user presses the ESC key.
Now, if you click on this Button, or press Esc then dialog Window is closing, but it does not work for the normal MainWindow.
To close the MainWindow, you can simply add a Click handler which has already been shown. But if you want a more elegant solution that would satisfy the MVVM style you can add the attached behavior:
public static class ButtonBehavior
{
#region Private Section
private static Window MainWindow = Application.Current.MainWindow;
#endregion
#region IsCloseProperty
public static readonly DependencyProperty IsCloseProperty;
public static void SetIsClose(DependencyObject DepObject, bool value)
{
DepObject.SetValue(IsCloseProperty, value);
}
public static bool GetIsClose(DependencyObject DepObject)
{
return (bool)DepObject.GetValue(IsCloseProperty);
}
static ButtonBehavior()
{
IsCloseProperty = DependencyProperty.RegisterAttached("IsClose",
typeof(bool),
typeof(ButtonBehavior),
new UIPropertyMetadata(false, IsCloseTurn));
}
#endregion
private static void IsCloseTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool && ((bool)e.NewValue) == true)
{
if (MainWindow != null)
MainWindow.PreviewKeyDown += new KeyEventHandler(MainWindow_PreviewKeyDown);
var button = sender as Button;
if (button != null)
button.Click += new RoutedEventHandler(button_Click);
}
}
private static void button_Click(object sender, RoutedEventArgs e)
{
MainWindow.Close();
}
private static void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
MainWindow.Close();
}
}
And in MainWindow use this Behavior like as:
<Window x:Class="MyProjectNamespace.MainWindow"
xmlns:local="clr-namespace:MyProjectNamespace">
<Button Name="CloseButton"
local:ButtonBehavior.IsClose="True" ... />

How to correctly implement a modal dialog on top a non-modal dialog?

In a WPF application I would like to implement the following behaviour which doesn't seem to work straightforward:
From the main window (Window1) the user opens a non-modal window (Window2), and that non-modal window may display a modal dialog (Window3).
The problem is that whenever the modal dialog has been shown, the main window disappears in the background (given that there are windows of other applications open) when the user closes the dialogs.
Is there anything wrong in the way that I use Window.Owner and Window.Show()/Window.ShowDialog(), is it a bug or is it something simply not supported?
The following simple WPF application demonstrates this behavior:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window2 win = new Window2();
win.Owner = this;
win.Show();
}
}
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window3 win = new Window3();
win.Owner = this;
win.ShowDialog();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
XAML Window1:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<Button Click="Button_Click">Show non-modal window</Button>
</Window>
XAML Window2:
<Window x:Class="WpfApplication1.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2">
<StackPanel>
<Button Click="Button_Click">Show modal dialog</Button>
<Button Name="btnClose" Click="btnClose_Click">Close</Button>
</StackPanel>
</Window>
XAML Window3:
<Window x:Class="WpfApplication1.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3">
<Button Name="btnClose" Click="btnClose_Click">Close</Button>
</Window>
UPDATE: Fixed copy&paste error in the code. This is .NET 3.5 SP1 in case it matters.
Microsoft confirms this as a bug in WPF:
This isn't a regression from previous releases so it doesn't make the bar to be fixed for this version of the product. We'll look into this for a future release.
In the meantime, this can be worked around by activating the owner window when the child window is closing.
Sample code:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void NonModalButtonClick(object sender, RoutedEventArgs e)
{
new Window1 { Owner = this }.Show();
}
private void ModalButtonClick(object sender, RoutedEventArgs e)
{
new Window1 { Owner = this }.ShowDialog();
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (this.Owner != null)
{
this.Owner.Activate();
}
}
}
(Note that the workaround will always bring the main window into foreground which might be different than the expected behavior)

Categories

Resources