XAML 嵌套模板绑定

XAML nested template binding

我有一个列表视图,我在其中使用 DataTemplateSelector 绑定了多个数据模板。但是,我无法构建我的项目,出现 "Object reference not set to an instance of an object" 错误。我将问题缩小到组合框的数据绑定 ItemsSource。如果我注释掉组合框,我的项目就会构建。据我了解, Binding 关键字在运行时进行评估,但这是一个编译时错误。我试图通过换出 x:Bind 来解决错误,因为它在编译时进行评估,但随后需要定义 DataTemplate 的类型。

x:DataType={x:Type templates:FilterDropdownDataTemplate}

但是,x:Type 未在 Windows 10 通用应用程序中定义。有什么建议吗?

这是我的 XAML:

<Page.Resources>
    <DataTemplate x:Name="DateComboboxTemplate">
        <TextBlock Text="{Binding}"/>
    </DataTemplate>

    <DataTemplate x:Name="FilterDropdownDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Value}"/>
            <ComboBox ItemsSource="{Binding DateRanges}"
                SelectionChanged="{Binding DateSelection}"
                SelectedItem="{Binding SelectedDateRange, Mode=TwoWay}"
                ItemTemplate="{StaticResource DateComboboxTemplate}">
            </ComboBox>
        </StackPanel>
    </DataTemplate>

    <config:MainFilterTemplateSelector
        x:Name="MainFilterSelector"
        FilterDropdownTemplate="{StaticResource FilterDropdownDataTemplate}"
        />
</Page.Resources>

<ListView x:Name="FilterCategories"
          Margin="0"
          Padding="0"
          BorderThickness="0"
          ItemsSource="{Binding Filters}"
          SelectedItem="{Binding SelectedFilterCategory, Mode=TwoWay}"
          IsItemClickEnabled="True"
          SelectionChanged="{x:Bind ViewModel.OpenSubFilters}"
          ItemTemplateSelector="{StaticResource MainFilterSelector}">
</ListView>

这里是相关的 C# 代码(我使用的是 MVVM 模式):

public class MainFilterViewDropdownListTemplate : Filter
{
    private ObservableCollection<string> _dateRanges;
    private string _selectedDateRange;

    public MainFilterViewDropdownListTemplate() : base()
    {
        _dateRanges = new ObservableCollection<string>();
    }

    public ObservableCollection<string> DateRanges
    {
        get
        {
            return _dateRanges;
        }
        set
        {
            SetProperty(ref _dateRanges, value);
            // hard coding these 4 lines for testing for now
            _dateRanges.Add("Last 7 days");
            _dateRanges.Add("Last 14 days");
            _dateRanges.Add("Last 30 days");
            _dateRanges.Add("Custom");
        }
    }

    public string SelectedDateRange
    {
        get
        {
            return _selectedDateRange;
        }
        set
        {
            SetProperty(ref _selectedDateRange, value);
        }
    }

    public IEnumerable<Filter> AllFilters { get; set; }

    public void InitializeFields(Filter filter)
    {
        Column = filter.Column;
        DisplayType = filter.DisplayType;
        ID = filter.ID;
        IsSelected = filter.IsSelected;
        ParentId = filter.ParentId;
        SelectedCount = filter.SelectedCount;
        TotalCount = filter.TotalCount;
        Value = filter.Value;
        visibility = filter.visibility;
    }

    private void DateSelection()
    {

    }
}

public class MainFilterTemplateSelector : DataTemplateSelector
{
    public DataTemplate FilterDropdownTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object selector)
    {
        if (selector == null)
        {
            throw new ArgumentNullException("Template is null");
        }
        if (!(selector is FilterBase))
        {
            throw new ArgumentException("This list can only be populated by a class that extends Filter.");
        }
        else
        {
            var filterType = selector as Filter;
            switch (filterType.DisplayType)
            {
                case "date":
                    return FilterDropdownTemplate;
                default:
                    return base.SelectTemplateCore(selector);
            }
        }
    }
}

public class Filter : FilterBase
{
    private int _selectedCount;
    private int _totalCount;
    private Visibility _visibility;

    public IEnumerable<Filter> Children
    {
        get;
        set;
    }

    public int TotalCount
    {
        get
        {
            return _totalCount;
        }
        set
        {
            SetProperty(ref _totalCount, value);
        }
    }

    public int SelectedCount
    {
        get
        {
            return _selectedCount;
        }
        set
        {
            SetProperty(ref _selectedCount, value);
        }
    }

    public Visibility visibility
    {
        get
        {
            return _visibility;
        }
        set
        {
            SetProperty(ref _visibility, value);
        }

    }

    public void InitializeAllChildren(IEnumerable<Filter> allFilters)
    {
        foreach (Filter item in allFilters)
        {
            item.Children = allFilters.GetAllChildrenFiltersForParentID(item.ID) as IEnumerable<Filter>;
            if (item.Children == null)
            {
                item.TotalCount = 0;
            }
            else
            {
                item.TotalCount = item.Children.Count();
                item.SelectedCount = item.Children.Where(t => t.IsSelected.Value).Count();
            }
        }
        Children = allFilters.GetAllChildrenFiltersForParentID(ID);
    }
}

public class FilterBase : ViewModelBase
{
    public int ID
    {
        get
        {

            return _id;
        }
        set
        {
            SetProperty(ref _id, value);
        }
    }



    public string Value
    {
        get
        {
            return _value;
        }

        set
        {
            SetProperty(ref _value, value);
        }
    }
    public string Column
    {
        get
        {
            return _column;
        }

        set
        {
            SetProperty(ref _column, value);
        }
    }

    public int ParentId
    {
        get
        {
            return _parentId;
        }

        set
        {
            SetProperty(ref _parentId, value);
        }
    }

    public string DisplayType
    {
        get
        {
            return _displayType;
        }

        set
        {
            SetProperty(ref _displayType, value);
        }
    }
    public bool? IsSelected
    {
        get
        {
            return _isSelected;
        }

        set
        {
            SetProperty(ref _isSelected, value);
        }
    }

    private int _id;
    private string _value;
    private string _column;
    private int _parentId;
    private string _displayType;
    private bool? _isSelected;
}

并且(BindableBase 来自 Prism.Mvvm 命名空间)

public class ViewModelBase : BindableBase, IDisposable
{
    PropertyChangeActionHelper _propertyChangeActionHelper;

    protected void RegisterPropertyChangeAction(Action action, params string[] monitoredProperties)
    {
        if (_propertyChangeActionHelper == null)
        {
            _propertyChangeActionHelper = new PropertyChangeActionHelper(this);
        }

        _propertyChangeActionHelper.RegisterPropertyChangeAction(action, monitoredProperties);
    }

    #region IDisposable Support

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_propertyChangeActionHelper != null)
            {
                _propertyChangeActionHelper.Dispose();
                _propertyChangeActionHelper = null;
            }
        }
    }

    ~ViewModelBase()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(false);
    }

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
}

假设声明了 templates 命名空间并且 FilterDropdownDataTemplate 是该命名空间中的一个类型,您应该能够定义 DataTemplate 的数据类型而无需 x:Type 使用以下语法:

<DataTemplate x:DataType="templates:FilterDropdownDataTemplate">