WindowsFormsHost ToolTipService - c#

Simple case code for a problem I'm having:
<Window x:Class="WFHTooltipEnableTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<WindowsFormsHost Name="HostControl">
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
</WindowsFormsHost>
<Button Content="Toggle" Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
using System.Windows;
using System.Windows.Controls;
namespace WFHTooltipEnableTest
{
public partial class MainWindow : Window
{
bool enabled = true;
public MainWindow() {}
private void Button_Click(object sender, RoutedEventArgs e)
{
enabled = !enabled;
ToolTipService.SetIsEnabled(this.HostControl, enabled);
}
}
}
The button will toggle the value passed to SetIsEnabled. When false, the thing hosted in the windows forms host control gets disabled.
Can't seem to find any explanation for this behavior.

Related

Open Popup from WPF Toolbar Button inside Overflow area

I have some buttons in a toolbar. One of the buttons opens a popup. It works fine when the button is clicked while the button is shown regularly. When the button is clicked while it is in the toolbars overflow area the popup does not work. It is shown and immediately closed. Is there a solution for this?
XAML
<Window x:Class="WpfApp5.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"
mc:Ignorable="d"
Title="MainWindow" Height="100" Width="100"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<DockPanel LastChildFill="True">
<ToolBar DockPanel.Dock="Top">
<Button Content="First"></Button>
<Button Content="Second"></Button>
<Button Content="Third"></Button>
<Button Content="Popup" Click="OnClick"></Button>
<Popup IsOpen="{Binding IsPopupOpen, Mode=TwoWay}" StaysOpen="False">
<Border BorderBrush="Black" BorderThickness="2">
<Grid Width="150" Height="150" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Popup"></TextBlock>
<Button Grid.Row="1" Content="Button In Popup" Click="PopupButtonOnClick"></Button>
</Grid>
</Border>
</Popup>
</ToolBar>
<Grid Background="White"></Grid>
</DockPanel>
</Window>
Code behind
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApp5
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private bool _isPopupOpen;
public MainWindow()
{
InitializeComponent();
}
public bool IsPopupOpen
{
get => _isPopupOpen;
set
{
if (value == _isPopupOpen) return;
_isPopupOpen = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void OnClick(object sender, RoutedEventArgs e)
{
IsPopupOpen = true;
}
private void PopupButtonOnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("I did it");
}
}
}

Access External Object From An Event Handler

Can anyone tell me how I can access an external object from an event handler?
The code below provides an example of what I'm trying to do. The references to externalClass in the event handler generate the following error message "The name 'externalClass' does not exist in the current context".
I've set the Assembly Output Type to Console Application so that it prints to the console.
Can anyone tell me how best to access the externalClass object from within the event handler?
The code is below:
XAML
<Window x:Class="AccessObjectFromEventHandler.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:AccessObjectFromEventHandler"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="auto" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Grid.Column="2" Width="100" Height=" 30" Content="Click to Fire Event" Click="Button_Click"/>
</Grid>
</Grid>
C#
using System;
using System.Windows;
namespace AccessObjectFromEventHandler
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ExternalClass externalClass = new ExternalClass();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine($"Button Click Event Fired.");
externalClass.Name = "Some Name";
externalClass.ExternalClassMethod();
}
}
public partial class ExternalClass
{
public string Name { get; set; }
// The access modifier is "public" to enable access from external types.
public void ExternalClassMethod()
{
Console.WriteLine($"ExternalClassMethod executed. Name = {Name}");
}
}
}
Try this:
using System;
using System.Windows;
namespace AccessObjectFromEventHandler
{
public partial class MainWindow : Window
{
ExternalClass externalClass;
public MainWindow()
{
InitializeComponent();
externalClass = new ExternalClass();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine($"Button Click Event Fired.");
externalClass.Name = "Some Name";
externalClass.ExternalClassMethod();
}
}
public partial class ExternalClass
{
public string Name { get; set; }
// The access modifier is "public" to enable access from external types.
public void ExternalClassMethod()
{
Console.WriteLine($"ExternalClassMethod executed. Name = {Name}");
}
}
}

In a WPF application using Visual Studio, how can I bind a usercontrol to a usercontrol variable?

I'm not sure if I asked the question correctly, because I am not finding the answer by searching the internet. I am creating a wizard window. I have a window that has a title at the top and buttons at the bottom that will stay there throughout changing the pages. So in the xaml.cs for the window, I have a list of UserControls that will contain all of the views for the wizard. I also have a property/field that holds the current view. I want to create a xaml UserControl tag that binds to the current view property. It should change when I change the current view property (I have already implemented the INotifyChanged interface). The current view property will be changed by c#. Here is the code that I have(simplified to show whats needed), and when I run it nothing shows in the view area:
WizardWindow.xaml:
<Window x:Class="WizardWindow.WizardWindow"...>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Text="Wizard Title"/>
</Grid>
<Grid Grid.Row="1">
<Border Name="WizardWindowPageContent" Margin="5" BorderBrush="Black" BorderThickness="1">
<!--This is what I have tried but isn't working -->
<UserControl Content="{Binding CurrentView}" />
</Border>
</Grid>
<Grid Grid.Row="2" Name="WizardButtons">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0">Cancel</Button>
<Button Grid.Column="2">Back</Button>
<Button Grid.Column="3">Next</Button>
</Grid>
</Grid>
</Window>
WizardWindow.xaml.cs:
using System;
...
using System.Windows.Controls;
namespace WizardWindow
{
public partial class WizardWindow : Window, INotifyPropertyChanged
{
// List of views in the config window
private List<UserControl> views;
// Current view showing in the window
private UserControl currentView;
public UserControl CurrentView
{
get { return currentView; }
set
{
currentView = value;
OnPropertyChanged("CurrentView");
}
}
// Used to keep track of the view index
private int viewIndex;
public WizardWindow ()
{
InitializeComponent();
// Set the screen to the center of the screen
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
views = new List<UserControl>();
views.Add(new FirstWizardPage(this));
viewIndex = 0;
CurrentView = views[viewIndex];
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
}
FirstWizardPage.xaml:
<!-- This should show up in the window -->
<UserControl x:Class="WizardWindow.FirstWizardPage" ... >
<Grid>
<TextBlock>Lorem Ipsum ...</TextBlock>
</Grid>
</UserControl>
FirstWizard.xaml.cs:
using System.Windows.Controls;
namespace WizardWindow
{
public partial class FirstWizardPage : UserControl
{
public FirstWizardPage(WizardWindow window)
{
InitializeComponent();
}
}
}
The given possible duplicate, Window vs Page vs UserControl for WPF navigation?
, is a good solution if I wanted to rewrite my program. However, it is not a solution to my exact problem. Someone else might have a similar problem and need this solution.
you need to use this:
<ContentControl x:Name="MyView"
Content="{Binding CurrentView}" />
It should work for you, but it's not MVVM.
You must binding on property DataContext of your user control, if you want to use MVVM.
I Will show little example for you:
It is MainWindow.xaml:
<Window x:Class="WpfApp2.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:WpfApp2"
xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Foo DataContext="{Binding UserControlViewModel}"/>
</Grid>
It is MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
It is MainWindowViewModel.cs:
public class MainWindowViewModel
{
public MainWindowViewModel()
{
UserControlViewModel = new UserControlViewModel{ Name = "Hello World" };
}
public UserControlViewModel UserControlViewModel { get; }
}
It is Foo.xaml:
<UserControl x:Class="WpfApp2.Foo"
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:WpfApp2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding Name}"/>
</Grid>
It is FooUsercontrolViewModel.cs
public class FooUserControlViewModel
{
public string Name { get; set; }
}

WPF Navigate to other page

I want to just navigate between pages
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void RouteItems(object sender, RoutedEventArgs e)
{
NavigationService nav = NavigationService.GetNavigationService(this);
nav.Navigate(new ItemsPage());
}
}
GetNavigationService returns null
<Window x:Class="Special.MainWindow"
Name="Window"
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:Special"
mc:Ignorable="d"
Title="MainWindow" WindowState="Maximized">
<Button Content="Go" Click="RouteItems"/>
</Window>
I don't want to use other method (changing Content).
EDIT
this.NavigationService is undefined
You need to, first add a Frame to your Xaml:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Frame x:Name="MainFrame"></Frame>
<Button Content="Go" Click="RouteItems" Grid.Row="1"/>
</Grid>
then after you add your xaml pages, use the MainFrame to navigate:
private void RouteItems(object sender, RoutedEventArgs e)
{
MainFrame.NavigationService.Navigate(new Uri("Page1.xaml", UriKind.RelativeOrAbsolute));
}

Catch button click on user control

I have a window with a button and usercontrol. Now when I click on the button, the raised event, I wanna catch on usercontrol. I guess this principle it called event tunneling. But I don't know too, if this way would be the right way to catch the button click event.
Example
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me"></Button>
<uc:Control Grid.Row="1"></uc:Control>
</Grid>
</Window>
UserControl
<UserControl x:Class="EventTunneling.Control"
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">
<Grid>
</Grid>
</UserControl>
Now i want to catch the event on the partial class of usercontrol, that was raised from main window. How can i do that?
namespace EventTunneling
{
/// <summary>
/// Interaction logic for Control.xaml
/// </summary>
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
}
}
Unfortunately, you're doing this all wrong. First, you need to data bind your collection from the code behind to the DataGrid.ItemsSource property. Then, when the Button is clicked, just handle it in the code behind, where you have access to the collection and simply save it however you like:
In UserControl:
<DataGrid ItemsSource="{Binding Items}" ... />
In MainWindow:
<Button Grid.Row="0" Content="Click me" Click="Button_Click" />
In code behind (you should implement the INotifyPropertyChanged interface on this property):
public ObservableCollection<YourDataType> Items { get; set; }
...
private void Button_Click(object sender, RoutedEventArgs e)
{
SaveAsXml(Items);
}
In code behind constructor (or set it in any valid way you prefer):
DataContext = this;
Make a public event on the window.
Fire the event when the button is clicked.
Subscribe to the event from your control
you can simply do this when the button is clicked make a call to a public method in your user Control :
namespace EventTunneling
{
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
public void CatchEventOnUserControl()
{
//do your job here
//....
}
}
}
then when the button is clicked call the CatchEventOnUserControl method
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me" Click="Button_Click"></Button>
<uc:Control x:Name="mycontrol" Grid.Row="1"></uc:Control>
</Grid>
and the code behind is
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
mycontrol.CatchEventOnUserControl();
}
}

Categories