Created
February 23, 2023 07:53
-
-
Save gekka/e828782889e5c74553af54b1db1cf8dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Window x:Class="WpfApp1.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:WpfApp1" | |
mc:Ignorable="d" | |
Title="MainWindow" Height="200" Width="300"> | |
<Window.Resources> | |
<!-- 添付プロパティでスタイルを指定していない場合のMenuItem --> | |
<Style TargetType="MenuItem"> | |
<Setter Property="Background" Value="LightBlue" /> | |
</Style> | |
</Window.Resources> | |
<StackPanel> | |
<!-- Popupを捕まえるイベントを用意して、TextBoxの標準のContextMenuをいじくる --> | |
<TextBox local:PopupTool.PopupLoaded="Popup_Loaded" Margin="5"> | |
<!-- ContextMenuに存在するMenuItemのスタイルを添付プロパティで追加指定できるように --> | |
<local:PopupTool.ContextMenuItemStyle> | |
<Style TargetType="{x:Type MenuItem}"> | |
<Setter Property="Background" Value="LightPink" /> | |
</Style> | |
</local:PopupTool.ContextMenuItemStyle> | |
</TextBox> | |
<!-- を添付プロパティで追加指定できるようにしない場合はリソースからMenuItem用のスタイルを適用 --> | |
<TextBox Margin="5"/> | |
<!-- RichTextBoxでも --> | |
<RichTextBox local:PopupTool.PopupLoaded="Popup_Loaded" Margin="5" /> | |
</StackPanel> | |
</Window> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Controls.Primitives; | |
namespace WpfApp1 | |
{ | |
public partial class MainWindow : Window | |
{ | |
public MainWindow() | |
{ | |
InitializeComponent(); | |
} | |
private void Popup_Loaded(object sender, RoutedEventArgs e) | |
{ | |
//TextBoxが標準で出すContextMenuにMenuItemを追加 | |
//IMEの項目などが追加されて普通の方法では出来ないので | |
if (e.OriginalSource is System.Windows.Controls.Primitives.Popup popup) | |
{ | |
if (popup.Child is ContextMenu cm) | |
{ | |
cm.Items.Add(new Separator()); | |
MenuItem mi = new MenuItem() { Header = "てすと" }; | |
for (int i = 1; i <= 2; i++) | |
{ | |
MenuItem subItem = new MenuItem() { Header = "さぶめにゅー" + i.ToString() }; | |
mi.Items.Add(subItem); | |
} | |
cm.Items.Add(mi); | |
} | |
} | |
} | |
} | |
} | |
namespace WpfApp1 | |
{ | |
public class PopupTool | |
{ | |
static PopupTool() | |
{ | |
// app.xamlのリソースに以下のスタイルを追加することと同じ | |
// <Style TargetType="Popup"> | |
// <Setter Property="local:PopupTool.Hook" Value="true" /> | |
// </Style> | |
Style style = new Style(typeof(Popup)); | |
style.Setters.Add(new Setter(PopupTool.HookProperty, true)); | |
Application.Current.Resources.Add(style.TargetType, style); | |
} | |
#region Popupが表示されるときを検出させるための添付プロパティ | |
//public static void SetHook(Popup obj, bool value) { obj.SetValue(HookProperty, value); } | |
private static readonly DependencyProperty HookProperty | |
= DependencyProperty.RegisterAttached("Hook", typeof(bool), typeof(PopupTool), new PropertyMetadata(false, OnPopupLoading)); | |
private static void OnPopupLoading(DependencyObject s, DependencyPropertyChangedEventArgs e) | |
{ | |
// 添付プロパティの値がSetterで設定されるタイミングを検出 | |
var p = (Popup)s; | |
var re = new RoutedEventArgs(PopupLoadedEvent, p); | |
var placementTarget = p.PlacementTarget; | |
if (placementTarget != null) | |
{ | |
var cm = p.Child as ContextMenu; | |
var styleContextMenu = GetContextMenuStyle(placementTarget); | |
if (styleContextMenu != null && styleContextMenu.TargetType.IsAssignableFrom(typeof(ContextMenu))) | |
{ | |
p.Resources[styleContextMenu.TargetType] = styleContextMenu; | |
cm.Style = styleContextMenu; | |
} | |
var styleMenuItem = GetContextMenuItemStyle(placementTarget); | |
if (styleMenuItem == null && p.PlacementTarget is FrameworkElement fe) | |
{ | |
//添付プロパティでMenuItemのスタイルが指定されていないならリソースからスタイルを探す | |
styleMenuItem = fe.TryFindResource(typeof(MenuItem)) as Style; | |
} | |
if (styleMenuItem != null && styleMenuItem.TargetType.IsAssignableFrom(typeof(MenuItem))) | |
{ | |
p.Resources[styleMenuItem.TargetType] = styleMenuItem; | |
//MenuItemを継承していてスタイルが自動的に適用されないMemuItemにスタイルを適用する | |
foreach (var item in cm.Items.OfType<MenuItem>()) | |
{ | |
item.Style = styleMenuItem; | |
} | |
} | |
//Popupが表示される前にRoutedEventを発生させる | |
p.PlacementTarget.RaiseEvent(re); | |
} | |
} | |
#endregion | |
#region Popupの表示されるときを通知するイベント | |
public static readonly RoutedEvent PopupLoadedEvent | |
= EventManager.RegisterRoutedEvent | |
("PopupLoaded", RoutingStrategy.Bubble, typeof(RoutedEventHandler) | |
, typeof(System.Windows.DependencyObject)); | |
public static void AddPopupLoadedHandler(DependencyObject element, RoutedEventHandler handler) | |
{ | |
if (!(element is UIElement uiElement)) | |
{ | |
return; | |
} | |
uiElement.AddHandler(PopupLoadedEvent, handler); | |
} | |
public static void RemovePopupLoadedHandler(DependencyObject element, RoutedEventHandler handler) | |
{ | |
if (!(element is UIElement uiElement)) | |
{ | |
return; | |
} | |
uiElement.RemoveHandler(PopupLoadedEvent, handler); | |
} | |
#endregion | |
#region Popupに表示されるContextMenuに適用するスタイルを指定するための添付プロパティ | |
public static Style GetContextMenuStyle(DependencyObject obj) { return (Style)obj.GetValue(ContextMenuStyleProperty); } | |
public static void SetContextMenuStyle(DependencyObject obj, Style value) { obj.SetValue(ContextMenuStyleProperty, value); } | |
public static readonly DependencyProperty ContextMenuStyleProperty | |
= DependencyProperty.RegisterAttached("ContextMenuStyle", typeof(Style), typeof(PopupTool), new PropertyMetadata(null)); | |
public static Style GetContextMenuItemStyle(DependencyObject obj) { return (Style)obj.GetValue(ContextMenuItemStyleProperty); } | |
public static void SetContextMenuItemStyle(DependencyObject obj, Style value) { obj.SetValue(ContextMenuItemStyleProperty, value); } | |
public static readonly DependencyProperty ContextMenuItemStyleProperty | |
= DependencyProperty.RegisterAttached("ContextMenuItemStyle", typeof(Style), typeof(PopupTool), new PropertyMetadata(null)); | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment