- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我面临着下一个误会。
序言:
我有 wpf 应用程序和下一个重要的 UI 部分:RadioButtons
和一些使用基于 Popup
的下拉菜单的控件(以组合框方式)。根据一些逻辑,每个单选按钮 Hook PreviewMouseDown
事件并做一些计算。在接下来的场景中,
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/
我面临着下一个误会。 序言: 我有 wpf 应用程序和下一个重要的 UI 部分:RadioButtons和一些使用基于 Popup 的下拉菜单的控件(以组合框方式)。根据一些逻辑,每个单选按钮 Hoo
我是一名优秀的程序员,十分优秀!