gpt4 book ai didi

c# - MouseButtonEventArgs.MouseDevice.DirectlyOver 误解

转载 作者:太空狗 更新时间:2023-10-29 22:01:11 25 4
gpt4 key购买 nike

我面临着下一个误会。

序言:

我有 wpf 应用程序和下一个重要的 UI 部分:RadioButtons和一些使用基于 Popup 的下拉菜单的控件(以组合框方式)。根据一些逻辑,每个单选按钮 Hook PreviewMouseDown事件并做一些计算。在接下来的场景中,

  1. 用户打开弹出窗口(不要选择任何东西,弹出窗口保持打开状态)
  2. 用户点击单选按钮

PreviewMouseDown不会像预期的那样为单选按钮触发(因为 Popup feature )。

我的目标是开火 PreviewMouseDown对于 RadioButton尽管有一个。

尝试解决:

快速而肮脏的解决方案是:hook PreviewMouseDown对于 Popup并重新开火PreviewMouseDown如果需要,使用新源事件,使用单选按钮作为源。可以通过 MouseButtonEventArgs.MouseDevice.DirectlyOver 获得新的来源.下一段代码就是这样做的(仅当 Popup 为外部点击“吃” PreviewMouseDown 时才会重新触发事件):

    private static void GrantedPopupPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var popup = sender as Popup;
if(popup == null)
return;

var realSource = e.MouseDevice.DirectlyOver as FrameworkElement;
if(realSource == null || !realSource.IsLoaded)
return;

var parent = LayoutTreeHelper.GetParent<Popup>(realSource);

if(parent == null || !Equals(parent, popup ))
{
e.Handled = true;
var args = new MouseButtonEventArgs(e.MouseDevice,
e.Timestamp,
e.ChangedButton)
{
RoutedEvent = UIElement.PreviewMouseDownEvent,
Source = e.MouseDevice.DirectlyOver,
};
realSource.RaiseEvent(args);
}
}

当我将该处理程序附加到 Popup.PreviewMouseDown 时,这运作良好直接通过 Behavior不工作(PreviewMouseDown 不会为单选按钮触发)如果我通过 EventManager.RegisterClassHandler 附加一个(目的是避免将行为附加到页面上可能出现的带有这些单选按钮的每个 Popup):

EventManager.RegisterClassHandler(
typeof (Popup),
PreviewMouseDownEvent,
new MouseButtonEventHandler(GrantedPopupPreviewMouseDown));

调试器显示e.MouseDevice.DirectlyOver (见上面的代码)是 Popup , 不是 Radiobutton (就像我通过 Behavior 附加处理程序时一样)!

问题:

如何以及为什么 MouseButtonEventArgs如果事件处理程序以两种不同的方式附加,则同一操作可以不同吗?

有人可以解释这种行为吗?

非常感谢。

最佳答案

组合框是作为用户从一组选项中进行选择的一种方式提供的,您可能希望这样做。但它还有其他契约(Contract)。它说用户应该专注于这个并且只关注这个任务。但那不是你的情况。您想要显示选项,让它们能够隐藏,并允许用户在显示选项时做其他事情。

我认为您需要一些其他控件而不是组合框。我的建议是使用包含列表框的扩展器。鉴于:

class NotificationObject : INotifyPropertyChanged
{
public void RaisePropertyChanged(string name)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

class ComboEntry : NotificationObject
{
public string Name { get; private set; }

private string _option = "Off";
public string Option
{
get { return _option; }
set { _option = value; RaisePropertyChanged("Option"); }
}

public ComboEntry()
{
Name = Guid.NewGuid().ToString();
}
}

class MyDataContext : NotificationObject
{
public ObservableCollection<ComboEntry> Entries { get; private set; }

private ComboEntry _selectedEntry;
public ComboEntry SelectedEntry
{
get { return _selectedEntry; }
set { _selectedEntry = value; RaisePropertyChanged("SelectedEntry"); }
}
public MyDataContext()
{
Entries = new ObservableCollection<ComboEntry>
{
new ComboEntry(),
new ComboEntry(),
new ComboEntry()
};
SelectedEntry = Entries.FirstOrDefault();
}
public void SetOption(string value)
{
Entries
.ToList()
.ForEach(entry => entry.Option = value);
}
}

我认为您需要以下 XAML:

<Window x:Class="RadioInCombo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RadioInCombo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MyDataContext x:Key="myDataContext" />
<DataTemplate x:Key="ComboEntryTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<Border Width="5" />
<TextBlock Text="{Binding Option}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel DataContext="{StaticResource myDataContext}">
<RadioButton x:Name="OnButton"
Content="On"
PreviewMouseDown="OnButton_PreviewMouseDown" />
<RadioButton x:Name="OffButton"
Content="Off"
PreviewMouseDown="OffButton_PreviewMouseDown" />
<Expander Header="{Binding SelectedEntry}"
HeaderTemplate="{StaticResource ComboEntryTemplate}">
<ListBox ItemsSource="{Binding Entries}"
ItemTemplate="{StaticResource ComboEntryTemplate}" />
</Expander>
</StackPanel>
</Window>

以及以下代码隐藏:

    private MyDataContext GetMyDataContext()
{
var candidate = FindResource("myDataContext") as MyDataContext;
if (candidate == null) throw new ApplicationException("Could not locate the myDataContext object");
return candidate;
}

private void OnButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
GetMyDataContext().SetOption("On");
}

private void OffButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
GetMyDataContext().SetOption("Off");
}

关于c# - MouseButtonEventArgs.MouseDevice.DirectlyOver 误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15876285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com