C#WPF无法从UserControl访问ControlTemplate中定义的按钮

时间:2013-10-24 20:55:40

标签: c# wpf xaml user-controls controltemplate

这是我在stackoverlow上的第一篇文章,我认为它是C#和WPF最好的在线帮助网站。

我在过去三天里研究了大约6个小时,试图找出如何将按钮处理程序事件附加到我在样式中定义的按钮。我的情况似乎与我在网上看到的所有其他例子不同。所以这里,我当然感谢你的意见。

来自MainWindow.xaml的片段,我在Grid中定义了以下

 <ScrollViewer Grid.Column="2" Grid.ColumnSpan="2" 
      HorizontalScrollBarVisibility="Visible" 
      VerticalScrollBarVisibility="Hidden"
      Background="AliceBlue">
    <ItemsControl ItemsSource="{Binding LaserDataItems}">
       <ItemsControl.ItemsPanel>
           <ItemsPanelTemplate>
               <StackPanel Orientation="Horizontal" Background="AliceBlue" />
       </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
    </ItemsControl> 
  </ScrollViewer>

LaserDataItems上的此绑定将包含要显示的UserControl列表。这些是根据需要动态创建的。但我实际上试图在控件的代码中完成我的所有工作(下面)

在我向您展示UserControl之前,这里是我将与UserControl一起使用的Style。 我的第一个目标是在加载按钮后在按钮上创建点击事件

<Style x:Key="HeaderStyle" TargetType="{x:Type DataGridColumnHeader}">            
  <Setter Property="Template">
     <Setter.Value>
        <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
           <Button   x:Name="MyButton"    Height="20"/>
        </ControlTemplate>
     </Setter.Value>
  </Setter>
</Style>

这是userControl

<UserControl x:Class="EClient.Controls.GetAllLaserData"
             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">
    <DataGrid Name="laserDataGrid" 
              ColumnHeaderStyle="{StaticResource HeaderStyle}"
              AutoGenerateColumns="False" 
              ItemsSource="{Binding }" 
              IsReadOnly="True" 
              RowHeaderWidth="0" 
              Height="567" 
              VerticalAlignment="Top" 
              RowHeight="17">
        <DataGrid.Columns>
            <DataGridTextColumn 
             Width="53" 
             Header="{Binding HeaderName}" 
             Binding="{Binding Name}"></DataGridTextColumn>
        </DataGrid.Columns>
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Setter Property="IsEnabled" Value="False"/>
            </Style>
        </DataGrid.RowStyle>
    </DataGrid>
</UserControl>

在此UserControl的DataGrid中是ColumnHeaderStyle,它被赋予模板:HeaderStyle。这个样式有一个按钮,我需要在实例化时附加一个单击处理程序。 我该怎么做呢。 我试图通过重写OnApplyTemplate方法来访问它,但我尝试的所有东西都返回null。当此方法运行时,按钮是否可能尚未实例化?必须有办法到达这个按钮。

当我运行它并成功创建这些UserControls的列表(它们是datagrids)时,可以在第一个单元格(每个网格的标题)中看到一个按钮。

我还尝试使用遍历可视化树的通用例程,但无济于事。实际上这是我应该追求的东西,我真的不知所措。


2013年10月26日增加了以下内容

虽然我找到了另一个解决这个问题的方法,但我仍然有兴趣解决它。我真的认为这是一个非常好的问题。

无论如何,我想我会画一张我想要做的事。也许这会对手头的问题有更好的认识。

Datagrid with Button Above Grid

1 个答案:

答案 0 :(得分:0)

不是一个直接的答案 - 但这是我如何解决问题。我不使用datagrids - 而是使用itemscontrols,所以我必须使用ItemsControl作为示例。

处理列表中的按钮时,我通常将包含按钮的控件拆分为自己的用户控件(根据需要应用样式)。然后我会在后台有一个事件处理程序,例如XAML

<UserControl x:Class="BindableTest.UserControls.CatItem"
             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="400">
  <StackPanel VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0 0 10 0">
    <Label Content="{Binding Path=Model.DisplayNumber}" HorizontalAlignment="Left" Height="25" Width="25" />
    <TextBox BorderBrush="Black" Text="{Binding Path=Model.SomeText, UpdateSourceTrigger=PropertyChanged}" Width="150" Height="25" />
    <StackPanel Orientation="Horizontal">
      <Button x:Name="btnDelete" Margin="5 0 0 0" Content="Delete" Click="btnDelete_Click_1"></Button>
    </StackPanel>
  </StackPanel>
</UserControl>

和代码背后......

  /// <summary>
  /// Interaction logic for CatItem.xaml
  /// </summary>
  public partial class CatItem : UserControl
  {
    public CatItem()
    {
      InitializeComponent();     
    }

    private void btnDelete_Click_1(object sender, RoutedEventArgs e)
    {
      if (DeleteClick != null)
        DeleteClick(sender, e);
    }

    public event RoutedEventHandler DeleteClick;


  }

从调用xaml,您可以使用此事件,如下所示。

<ItemsControl x:Name="itmsList" ItemsSource="{Binding Path=ModelListVMs}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal"></StackPanel>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <uc:CatItem DeleteClick="ItemDeleteClick"></uc:CatItem> <!-- Using click here -->
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

在窗口的背景中,您可以选择任何按钮的事件。

public void ItemDeleteClick(object sender, RoutedEventArgs e)
    {
      var ctx = (sender as Button);

      //can get datacontext and other properties easily from here  
    }

对不起,这不是一个直接的答案,但希望它会帮助你朝着正确的方向发展。