简体   繁体   English

Silverlight数据绑定错误

[英]Silverlight DataBinding Error

I've a GridView which has RowDetail . 我有一个具有RowDetailGridView I want to each time user clicks on the rows get some detail from database, I use Telerik GridView . 我想每次用户单击行从数据库中获取一些细节时,我都使用Telerik GridView In normal way it's not possible or at least I don't know how, because RowDetail context binded directly to the grid DataContext , what I want is more than what GridRow contains it. 通常,这是不可能的,或者至少我不知道如何做,因为RowDetail上下文直接绑定到网格DataContext ,我想要的不仅仅是GridRow包含的内容。 What I found is maybe I can set RowDetailTemplate DataContext to UserControl by naming the UserControl so I can reference RowDetail to other model. 我发现的是,也许可以通过命名UserControl来将RowDetailTemplate DataContext设置为UserControl ,以便可以将RowDetail引用到其他模型。 My code is something like this 我的代码是这样的

    <UserControl
    x:Name="mainPageView"
    x:Class="Project.Client.TestView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView" 
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
        <DataTemplate x:Key="ContactRowDetailTemplate" >
            <Grid Background="Transparent"
                DataContext="{Binding DataContext.ContactStatModel, 
                ElementName=mainPageView,Mode=OneTime}">
                <Grid.RowDefinitions>
                    <RowDefinition Height="28" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="Sent SMS Count" Grid.Column="0" Grid.Row="0" />
                <TextBlock Text=":" Grid.Column="1" Grid.Row="0" />
                <TextBlock Text="{Binding SMSCount}" Grid.Column="2" Grid.Row="0" />

            </Grid>
        </DataTemplate>
    </UserControl.Resources>

    <telerik:RadGridView  
        x:Name="gridView"
        AutoGenerateColumns="False" Height="Auto" Grid.Row="3"
        ItemsSource="{Binding VOutboxList, Mode=TwoWay}"
        SelectedItem="{Binding VOutboxModel, Mode=TwoWay}"
        RowDetailsTemplate="{StaticResource ContactRowDetailTemplate}"
        LoadingRowDetails="gridView_LoadingRowDetails">
        <telerik:RadGridView.Columns>
            <telerik:GridViewDataColumn UniqueName="FirstName"  Header="First Name" Width="150" />
            <telerik:GridViewDataColumn UniqueName="LastName" Header="Last Name" Width="150" />
        </telerik:RadGridView.Columns>
    </telerik:RadGridView>

</UserControl>

But this time I get this exception 但是这次我得到这个例外

{Error: System.Exception: BindingExpression_CannotFindElementName}

Any advice will be helpful. 任何建议都会有所帮助。 Best Regards. 最好的祝福。

The reason for this is that WPF's and Silverlights DataGrid columns live outside the logical tree and thus make it impossible to use a binding source specified using ElementName which is common when referencing ViewModel properties such as commands from within DataGrid Template Columns. 原因是WPF和Silverlights DataGrid列位于逻辑树之外,因此无法使用通过ElementName指定的绑定源,该绑定源在引用ViewModel属性(例如从DataGrid Template Columns内引用命令)时很常见。 For more information about this problem see: http://blogs.msdn.com/b/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx 有关此问题的更多信息,请参见: http : //blogs.msdn.com/b/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx

The class below act's as glue between the column and the world around it. 下面的类充当列与周围世界之间的黏合剂。 It was written for Silverlight's built-in DataGrid but should be easy enough to adapt it for the Telerik Grid. 它是为Silverlight的内置DataGrid编写的,但应该足够容易使其适合Telerik Grid。 It can be used like this: 可以这样使用:

<DataTemplate x:Key="ContactRowDetailTemplate" >
  <Grid Background="Transparent"
    DataContext="{Binding ParentDataGrid.DataContext.ContactStatModel, 
    ElementName=shim,Mode=OneTime}">
        <Shims:DataGridShim x:Name="shim"/>
    <Grid.RowDefinitions>
      <RowDefinition Height="28" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <TextBlock Text="Sent SMS Count" Grid.Column="0" Grid.Row="0" />
    <TextBlock Text=":" Grid.Column="1" Grid.Row="0" />
    <TextBlock Text="{Binding SMSCount}" Grid.Column="2" Grid.Row="0" />
  </Grid>
</DataTemplate>

public class DataGridShim : FrameworkElement
{
  /// <summary>
  /// Initializes a new instance of the <see cref="DataGridShim"/> class.
  /// prepares the ParentDataGrid property for consumption by sibling elements in the DataTemplate
  /// </summary>
  public DataGridShim()
  {
    Loaded += (s, re) =>
    {
      ParentDataGrid = GetContainingDataGrid(this);
    };
  }

  /// <summary>
  /// Gets or sets the parent data grid.
  /// </summary>
  /// <value>
  /// The parent data grid.
  /// </value>
  public DataGrid ParentDataGrid { get; protected set; }

  /// <summary>
  /// Walks the Visual Tree until the DataGrid parent is found and returns it
  /// </summary>
  /// <param name="value">The value.</param>
  /// <returns>The containing datagrid</returns>
  private static DataGrid GetContainingDataGrid(DependencyObject value)
  {
    if (value != null)
    {
      DependencyObject parent = VisualTreeHelper.GetParent(value);
      if (parent != null)
      {
        var grid = parent as DataGrid;
        if (grid != null)
          return grid;

        return GetContainingDataGrid(parent);
      }

      return null;
    }

    return null;
  }
}

I've even simplified the accepted solution. 我什至简化了公认的解决方案。 It uses the trick that from DataTemplates, you can reference static resources. 它使用了从DataTemplates中可以引用静态资源的技巧。 And in static resources, you can use ElementName in binding. 在静态资源中,可以在绑定中使用ElementName。

  1. Create a new control: 创建一个新的控件:

     public class ElementProxy : DependencyObject { public DependencyObject Element { get { return (DependencyObject)GetValue(ElementProperty); } set { SetValue(ElementProperty, value); } } public static readonly DependencyProperty ElementProperty = DependencyProperty.Register("Element", typeof(DependencyObject), typeof(ElementProxy), new PropertyMetadata(null)); } 
  2. Put it into static resources of the DataGrid or its parent control and reference it through StaticResource: 将其放入DataGrid或其父控件的静态资源中,并通过StaticResource进行引用:

     <UserControl.Resources> <helpers:ElementProxy Element={Binding ElementName=mainPageView} x:Key="Proxy" /> </UserControl.Resources> 

(in column template:) (在列模板中:)

    <DataTemplate>
        <Grid DataContext={Binding Element.DataContext,Source={StaticResource Proxy}} />
    </DataTemplate>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM