从绑定的用户控件中访问数据上下文

5

我已经从ObservableCollection创建了一个动态的UserControl,如下所示...

 public  static ObservableCollection<Model.Model.ControleData> ListControleMachine = new ObservableCollection<Model.Model.ControleData>();

     public Genkai(string Autorisation) {
                InitializeComponent();
    
                DataContext = this;
               
               icTodoList.ItemsSource = ListControleMachine;
               Model.Model.ControleData v = new Model.Model.ControleData();
               v.ComputerName = "M57095";
               v.ImportSource = "LOAD";
               ListControleMachine.Add(v);
    }

XAML

<ItemsControl x:Name="icTodoList" ItemsSource="{Binding ListControleMachine}" >
   <ItemsControl.ItemTemplate>
      <DataTemplate DataType="{x:Type local:ControlMachineII}">
         <local:ControlMachineII  />                                        
      </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>

但是我怎样才能从C#代码中访问DataContext呢?

比如说,我想删除一个带有关闭按钮的UserControl,我至少需要访问ControleData.ComputerName的值,然后将其从Mainform.ListControleMachine中移除。

我找不到最佳实践来完成这个目标并在UserControl代码中操作我的数据。

删除按钮代码应该像这样(使用硬编码的值):

  Genkai.ListControleMachine.Remove(Genkai.ListControleMachine.Where(X => X.ComputerName == "M57095").Single());
2个回答

1
我最终发现我的DataContext在启动时尚未初始化,这就是为什么我会出错,所以我必须先等待数据上下文:以下是更正的代码。
     public ControlMachineII()
            {
                InitializeComponent();
                DataContextChanged += new DependencyPropertyChangedEventHandler(ControlMachineII_DataContextChanged);


            }

   private void ControlMachineII_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            string compname = (this.DataContext as Model.Model.ControleData).ComputerName;
            Console.WriteLine("DataContext initialized computername :" +compname);
        }

1
你知道,针对一个非常小的问题(肯定是对象引用错误),你写了一个非大而整的问题定义,并且完全偏离了实际问题。 - Kylo Ren
非常有用的答案 - 谢谢。我有一种直觉,即在组件初始化时数据上下文尚不可用,但这向我展示了如何在其更改时访问它。 - Tim Holt

0

我看到你今天发布了同样的问题, 并且提供了更多的数据。我将使用那些数据来提出解决方案。

解决方案 1:

像下面这样使用按钮的标签属性:

<Button Content="Close this UC" HorizontalAlignment="Left" Margin="414,22,0,0" 
            VerticalAlignment="Top" Width="119" Click="Button_Click" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />

事件处理程序:

private void Button_Click(object sender, RoutedEventArgs e)
    {
         var button = sender as Button;
         List<object> list = (button.Tag as ItemsControl).ItemsSource.OfType<TodoItem>().ToList<object>();
        list.Remove(button.DataContext);
        (button.Tag as ItemsControl).ItemsSource = list;
    }

解决方案2:

更优雅的解决方案:

在您的MainWindow中创建此Style

<Window.Resources>
    <Style TargetType="Button">
        <EventSetter Event="Click" Handler="Button_Click"/>
    </Style>
</Window.Resources>

所以现在任何一个MainWindow的后代Button控件中的Button Click事件的处理程序都在MainWindow.xaml.cs中。
然后将handler方法放置在MainWindow.xaml.cs中,并像下面这样更改handler
private void Button_Click(object sender, RoutedEventArgs e)
    {
        var button = sender as Button;
        items.Remove(button.DataContext as TodoItem);
        icTodoList.ItemsSource = null;
        icTodoList.ItemsSource = items;            
    }

我的意思是,如果我的控件需要发送一个带有计算机名称的SQL查询,我必须从标签内容中获取它吗?我认为我可以简单地检索到绑定到当前控件的控件数据对象,这将更好。 - Zwan
@Zwan computername是ControleData的一个属性,它将是ItemsControl项目的DataContext。因此,在代码后台中,您可以获取ControlMachineII.DataContext,它将是一个ControleData对象。我理解您的问题了吗?还是有其他问题? - Kylo Ren
但是我在谈论用户控件代码后台,因此它应该是 var MyData = this.dataContext as ControleData,然后我会得到 MyData.ComputerName,但这不是它运作的方式,我不明白为什么? - Zwan
对于您的查询问题,您可以根据情况使用“祖先绑定”或“元素绑定”。WPF旨在使事物更少耦合,因此需要更多编码、转换和通用引用。 - Kylo Ren
好的,我明白了。当这段代码放在UC按钮代码中时,它可以工作:Console.WriteLine((this.DataContext as Model.Model.ControleData).ComputerName); 但是如果我把它放在InitializeComponent()下面,它就不能工作了。这让我很困扰,因为我想在那里使用上下文来实例化一些变量。如果有人能告诉我原因,那就太好了,因为它会抛出TargetInvocationException异常。 - Zwan
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接