我的表单上有一个UserControl
Button
点击后,会在新行或列中添加UserControl
或另一个UserControl
的另一个实例。我要做的是点击Button
时,找出包含UserControl
的{{1}}所在的列,然后将新Button
添加到该列同一栏。代码如下:
UserControl
我遇到的问题是获取 ++rowCount;
int currentColumn = Grid.GetColumn(e.Source as UIElement);
AnswerNode answerNode = new AnswerNode();
answerNode.buttonAddQuestionNode.MouseLeftButtonDown += AddQuestionNode_DifferentLevelEvent;
answerNode.Margin = new Thickness(0, 5, 0, 5);
RowDefinition gridRowNew = new RowDefinition();
gridRowNew.Height = new GridLength(70);
Grid.SetRow(answerNode, rowCount);
Grid.SetColumn(answerNode, currentColumn);
MainGrid.RowDefinitions.Add(gridRowNew);
MainGrid.Children.Add(answerNode);
的列索引会导致e.Source
中的按钮索引 - 在本例中为UserControl
- 而不是1
本身的列索引。我如何访问UserControl
的列索引,该列索引是被点击的UserControl
的父级?
答案 0 :(得分:0)
Without a good, minimal, complete code example that clearly illustrates the question, showing exactly what you've tried and how you want the event handling to work, it's difficult to know for sure what the best answer would be. That said, from what little code you've provided and your problem description, it sounds like you have subscribed to the event in the wrong control object. Specifically, you have declared your event handler in the Button
object directly, rather than subscribing to the Button.Click
event in the UserControl
.
For a routed event, you can always get the original source of the event, i.e. the control where the event was initially signaled via the RoutedEventArgs.OriginalSource
property. The RoutedEventArgs.Source
property in turn will provide the reference to the control object to which the event has been routed and is currently handling the event. If you want to handle the event as seen by the UserControl
object, then you need to subscribe to the event from the UserControl
object, not the Button
object.
Here is a short, complete code example that illustrates the basic technique:
<UserControl x:Class="TestSO33441926RoutedEvent.UserControl1"
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.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Click here: "/>
<Button x:Name="button1" Content="Click me!" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Top"
Click="Button_Click"/>
</Grid>
</UserControl>
<Window x:Class="TestSO33441926RoutedEvent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TestSO33441926RoutedEvent"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="MainWindow column 1"/>
<TextBlock Text="MainWindow column 2" Grid.Column="1"/>
<l:UserControl1 x:Name="userControl1" Grid.Column="2"
Button.Click="UserControl1_Click"/>
</Grid>
</Window>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
App.ReportClick((FrameworkElement)e.Source);
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UserControl1_Click(object sender, RoutedEventArgs e)
{
App.ReportClick((FrameworkElement)e.Source);
}
}
public partial class App : Application
{
public static void ReportClick(
FrameworkElement frameworkElement, [CallerMemberName]string callerName = null)
{
MessageBox.Show(
"Caller name: \"" + callerName + "\"\n" +
"Sender name: \"" + frameworkElement.Name + "\"\n" +
"Sender column: " + Grid.GetColumn(frameworkElement));
}
}
Since neither event handler sets RoutedEventArgs.Handled
to true
, the event will be sent to each handler in turn, starting with the original source of the event and moving up the visual object graph to each parent in turn.
As such, you can see that when the ReportClick()
method is called by each event handler, the e.Source
object is different in each event handler, depending on where that handler was subscribed.
For your own question, the key is here, in the MainWindow.xaml
source code:
<l:UserControl1 x:Name="userControl1" Grid.Column="2"
Button.Click="UserControl1_Click"/>
Note that the Button.Click
event is the one being subscribed, but that the code is subscribing from the UserControl1
object. This has the result that the event handler void UserControl1_Click(object, RoutedEventArgs)
is called with the UserControl1
object as the sender and source of the event.
Thus, when the column index of the sender of the event is retrieved by calling Grid.GetColumn(UIElement)
, the column index of the UserControl1
object is returned, not the column index of the original source of the event (i.e. the Button
object that was actually clicked).
As an aside: in the bit of code your posts shows, there seems to be a fair amount of code-behind that is probably better-implemented as XAML declarations. Naturally, just about anything you can do in XAML, you can also accomplish in code-behind. But that doesn't mean it's a good idea. Addressing that defect in your code is not likely to relate directly to the question you're asking, nor would changing the implementation in that way fix the problem. But you should definitely consider seriously following the WPF/XAML paradigm more closely and put as much of your implementation in XAML as you can.