我有一个UserControl
,我在其中使用一个Canvas
,在那个 Canvas 中使用一个 Rectangle。我想为该用户控件(画布和矩形)创建一个单击事件,然后我想在主窗口中使用它。
问题是:我想为UserControl
. 怎么做?请显示小示例或代码。
我有一个UserControl
,我在其中使用一个Canvas
,在那个 Canvas 中使用一个 Rectangle。我想为该用户控件(画布和矩形)创建一个单击事件,然后我想在主窗口中使用它。
问题是:我想为UserControl
. 怎么做?请显示小示例或代码。
关于如何从主窗口可以注册的 UserControl 公开事件的简要示例:
在您的用户控件中:
1. 添加以下声明:
public event EventHandler UserControlClicked;
2. 在您的 UserControl_Clicked 事件中引发如下事件:
private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (UserControlClicked != null)
{
UserControlClicked(this, EventArgs.Empty);
}
}
在您的 MainWindow 中:
您的用户控件现在将有一个UserControlClicked
您可以注册到的事件:
<local:UserControl1 x:Name="UC" UserControlClicked="UC_OnUserControlClicked" />
我发现这更容易将值传递给处理程序:
public event Action<string> onUserCodeFetched;
private void btnEnterClicked(object sender, RoutedEventArgs e)
{
onUserCodeFetched(PersonellCode.Text);
PersonellCode.Text = "";
}
这是一个老问题,但我也发现使用类似属性的自定义事件绕过事件很有用,就像这里一样。您可以使用通用的 EventHandler,也可以更具体(RoutedEventHandler、MouseButtonEventHandler 等)来避免以后的强制转换。例如,要绕过点击事件,您可以在自定义控件类中编写:
public readonly object objectLock = new object();
public event RoutedEventHandler CustomClick
{
add{ lock (objectLock) { myClickableInnerControl.Click += value;}}
remove {lock (objectLock) { myClickableInnerControl.Click -= value; }}
}
对于PreviewMouseDown 事件,它类似于:
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock) { myInnerControl.PreviewMouseDown += value;}}
remove {lock (objectLock) { myInnerControl.PreviewMouseDown -= value; }}
}
在这种情况下,myInnerControl 将是您的画布。
然后您可以将 xaml 中的事件初始化为
<local:myClickableControl x:Name="ClickCtrl1" CustomClick="ClickCtrl1_CustomClick" />
或者
<local:myCustomControl x:Name="CustomCtrl1" CustomPreviewMouseDown="CustomCtrl1_CustomPreviewMouseDown" />
从后面的代码:
ClickCtrl1.CustomClick+=ClickCtrl1_CustomClick;
或者
CustomCtrl1.CustomPreviewMouseDown+=CustomCtrl1_CustomPreviewMouseDown;
您还可以订阅多个内部控件事件的回调(当它们重叠时要小心,因为某些事件(例如 previewMouseDown 不仅由前面的控件触发,而且由下面的控件触发)。
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock)
{
myInnerControl1.PreviewMouseDown += value;
myInnerControl2.PreviewMouseDown += value;
}}
remove {lock (objectLock)
{
myInnerControl1.PreviewMouseDown -= value;
myInnerControl2.PreviewMouseDown -= value;
}}
}
(如果内部控件部分重叠,可以在回调方法中使用对应的 eventArgs Handled 属性来避免重复)
最后,您可以为内部控件触发的事件添加一层控件:
bool MousePreviewDownUsed = false;
event MouseButtonEventHandler _myPreviewMouseDownEvent = null;
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add
{
lock (objectLock)
{
_myPreviewMouseDownEvent += value;
if (value != null && !MousePreviewDownUsed)
{
myInnerControl.PreviewMouseDown += myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = true;
}
}
}
remove
{
lock (objectLock)
{
if (_myPreviewMouseDownEvent != null)
{
_myPreviewMouseDownEvent -= value;
if ((_myPreviewMouseDownEvent == null ||
_myPreviewMouseDownEvent.GetInvocationList().Length == 0)
&& MousePreviewDownUsed)
{
_myPreviewMouseDownEvent = null;
myInnerControl.PreviewMouseDown -= myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = false;
}
}
}
}
}
private void myInnerControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// Do some previous operations or control whether the event must be broadcasted
_myPreviewMouseDownEvent?.Invoke(sender, e);
}
这个事件是从 xaml 或后面的代码以与以前相同的方式初始化的。