Search code examples
c#wpfxamldatatemplate

DataTemplate doesn't properly bind the properties as specified


I have the following DataTemplate in DataTemplates.xaml

<DataTemplate DataType="{x:Type local:ExcelReportVM}">
    <local:ExcelReport DoubleClickHandler="{Binding}">
        <local:ExcelReport.RowColorConverter>
            <local:ReportRowColorConverter/>
        </local:ExcelReport.RowColorConverter>
    </local:ExcelReport>
</DataTemplate>

I make sure that this DataTemplate is usable within the application scope via the following App.xaml definition:

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="DataTemplates.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

And this is my control ExcelReport.xaml:

<UserControl x:Class="WpfApplication1.ExcelReport"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              ....
             xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <DataTemplate x:Key="HeaderTemplate">
            <TextBlock TextAlignment="Center" Text="{Binding .}" TextWrapping="WrapWithOverflow" />
        </DataTemplate>

    </UserControl.Resources>
    <UserControl.DataContext>
        <local:ExcelReportVM/>
    </UserControl.DataContext>
    <syncfusion:SfDataGrid ItemsSource="{Binding Entries}" x:Name="grid" Background="White"
                           HeaderTemplate="{StaticResource HeaderTemplate}"

                           SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=UserControl}}">
    </syncfusion:SfDataGrid>
</UserControl>

My code behind: ExcelReport.xaml.cs

   public partial class ExcelReport : UserControl
    {


  public static readonly DependencyProperty RowColorConverterProperty = DependencyProperty.Register(
              "RowColorConverter",
              typeof(IValueConverter),
              typeof(ExcelReport),
              new FrameworkPropertyMetadata(new PropertyChangedCallback(OnRowColorConverterChanged))
            );

    public IValueConverter RowColorConverter
        {
            get { return (IValueConverter)GetValue(RowColorConverterProperty); }
            set { SetValue(RowColorConverterProperty, value); }
        }

   public ExcelReport()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
        }

 private void OnLoaded(object sender, RoutedEventArgs e)
{  
    Debug.Assert(DataContext.GetType()==typeof(ExcelReportVM)); //DataContext is correct
    Debug.Assert(RowColorConverter!=null); //but this is null
  }
}

I've no idea why I can successfully bind the DataContext, but the <DataTemplate DataType="{x:Type local:ExcelReportVM}"> that I define is not used, I thought everything inside the DataTemplates.xaml is accessible to ExcelReport.xaml?

Note: There is no error in the output window, and there is no exception been thrown anywhere in the code.


Solution

  • This is how I fix the problem, I don't set the UserControl.DataContext to ExcelReportVM at ExcelReport.xaml; instead, I set the ContentControl.Content to ExcelReportVM at MainWindow.xaml.

    Updated code at ExcelReport.xaml:

    <UserControl x:Class="WpfApplication1.ExcelReport"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  ....
                 xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
                 d:DesignHeight="300" d:DesignWidth="300">
        <UserControl.Resources>
            <DataTemplate x:Key="HeaderTemplate">
                <TextBlock TextAlignment="Center" Text="{Binding .}" TextWrapping="WrapWithOverflow" />
            </DataTemplate>
    
        </UserControl.Resources>
      <!--  <UserControl.DataContext>   this is not longer needed
            <local:ExcelReportVM/>
        </UserControl.DataContext> -->
        <syncfusion:SfDataGrid ItemsSource="{Binding Entries}" x:Name="grid" Background="White"
                               HeaderTemplate="{StaticResource HeaderTemplate}"
    
                               SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=UserControl}}">
        </syncfusion:SfDataGrid>
    </UserControl>
    

    Code at MainWindow.xaml

    <Syncfusion:RibbonWindow x:Class="WpfApplication1.MainWindow"
                ...
            xmlns:local="clr-namespace:WpfApplication1"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525" WindowState="Maximized"
            Syncfusion:SkinStorage.VisualStyle="Office2013"
            xmlns:Syncfusion="http://schemas.syncfusion.com/wpf">
    
        <Grid x:Name="ExcelReport22">
            <ContentControl>   <!-- this is where the ExcelReportVM is binded to -->
                <local:ExcelReportVM/>
            </ContentControl>
    
        </Grid>
    </Syncfusion:RibbonWindow>