【问题标题】:Markup extension does not work at design time标记扩展在设计时不起作用
【发布时间】:2014-12-02 09:41:02
【问题描述】:

我有标记扩展允许我同时在GridView 中使用绑定和单元格模板。它在运行时工作正常,但在设计时不起作用,想知道我是否可以做些什么来解决这个问题。我已经测试了返回简单字符串而不是 DataTemplate 只是为了确保自定义标记扩展在设计时通常工作 - 它工作,所以它应该在某种程度上与返回 DataTemplate 的事实有关。

[MarkupExtensionReturnType(typeof(DataTemplate))]
public class TemplateBuilderExtension : MarkupExtension
{
    public string Path { get; set; }

    public TemplateBuilderExtension() { }
    public TemplateBuilderExtension(string path)
    {
        Path = path;
    }

    // Here be dirty hack.
    internal static string TagPath { get; private set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        TagPath = Path;
        var resourceExt = new StaticResourceExtension("GridViewTextCell");

        // This line causes the evaluation of the Tag as the resource is loaded.        
        var baseTemplate = (DataTemplate)resourceExt.ProvideValue(serviceProvider);

        return baseTemplate;
    }
}

[MarkupExtensionReturnType(typeof(BindingExpression))]
public class TemplateBuilderTagExtension : MarkupExtension
{
    public TemplateBuilderTagExtension()
    {           
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return new Binding(TemplateBuilderExtension.TagPath);
    }
}

<Window.Resources>
    <DataTemplate x:Shared="false" x:Key="GridViewTextCell">
        <Border BorderBrush="Blue" BorderThickness="1">
            <TextBlock Text="{markupExtensions:TemplateBuilderTag}"></TextBlock>
        </Border>
    </DataTemplate>
</Window.Resources> 
<Grid>      
    <ListView SelectedIndex="5">        
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Id" CellTemplate="{markupExtensions:TemplateBuilder Id}" Width="300"/>
            </GridView>
        </ListView.View>
    </ListView>        
</Grid>

更新:我已将代码简化为尽可能短,在实际情况下,有多个 GridView 通过应用程序,每个网格包含多个列,这些列应该重用相同的模板,而且由于性能原因我不能使用 DataGrid问题。

【问题讨论】:

  • 我还不知道这个。 “使用绑定和单元格模板”是什么意思?您是否想要 celltemplate 中的视觉父母的数据上下文?然后你可以走一个更简单的方法
  • 问题是,如果你想使用单元格模板,你需要为每一列定义它,因为你不能将绑定路径传递给单元格模板。有问题的代码解决了问题。
  • 那不是数据模板选择器的候选者吗?
  • 从 GridViewRowPresenter 代码看来它没有帮助 - 它只是使用类来选择单元格模板,但不会对绑定做任何事情。
  • 在您的情况下,它是 CellTemplateSelector,它允许您为您的列选择适当的模板。那么就不需要使用模板绑定了。

标签: c# wpf xaml design-time markup-extensions


【解决方案1】:

我最近也遇到了这个问题。 结果,不知何故,我在 WPF 设计器中禁用了项目代码。 启用项目代码使标记扩展按预期工作。

取自docs.microsoft.com

【讨论】:

  • 永远不要低估小按钮。
  • 谢谢你。为什么我的自定义控件都没有突然在设计器中呈现,这让我大吃一惊。
【解决方案2】:

您的扩展没有多大意义。这一切都可以这样写:

<Window.Resources>
    <sys:String x:Key="path">thatPath<sys:String/>

    <DataTemplate x:Shared="false" x:Key="GridViewTextCell">
        <Border BorderBrush="Blue" BorderThickness="1">
            <TextBlock Text="{Binding Path={StaticResource path}}"></TextBlock>
        </Border>
    </DataTemplate>
</Window.Resources> 
<Grid>      
    <ListView SelectedIndex="5">        
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Id" CellTemplate="{StaticResource GridViewTextCell}" Width="300"/>
            </GridView>
        </ListView.View>
    </ListView>        
</Grid>

绑定本身也是一种扩展。你有点试图扩展一个扩展......

要不要让它保持原样并使用正常的方法呢? :)

【讨论】:

  • 好的,如果单元格模板足够复杂,您不想通过应用程序中的所有 GridView 对 GridView 中的每一列重复它怎么办?假设您需要在一个网格中有 10 列,并且所有列都应该使用相同的单元格模板,但绑定不同(绑定很简单,相同的视图模型,不同的属性)?
  • 很遗憾,这样不行,只要你设置了DisplayMemberBindingCellTemplate的属性值就被忽略了。
  • 我不这么认为 :) 它对我有用。你能上传你的项目吗?
  • 如果你看一下 GridViewRowPresenter source,CreateCell 方法,你会注意到,如果设置了 DisplayMemberBiding,则只创建 TextBlock,所以你应该看不到我的示例中的边框。
  • 我查看了那个链接。你是对的。我想我把 GridView 和 DataGrid 混合在一起了。你的问题真的很愚蠢。也许这个链接会进一步帮助你。 msdn.microsoft.com/en-us/library/ms752313(v=vs.110).aspx 关于使用 GridViewRowPresenter。顺便说一句,你试试 DataGrid 怎么样?
【解决方案3】:

所以我决定使用以下方法:

<GridViewColumn Header="TestColumn">
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding TestProperty}" ContentTemplate="{StaticResource GridViewTextCell}" />
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>

因此,将模板包装到ContentPresenter 允许使用我希望的绑定并重用模板。

在此之后,可以走得更远,我有工作概念,但决定不使用它(至少现在)。想法是通过获取 ItemsSource 的公共属性来自动生成列,这可能会通过创建属性来进一步改进,该属性将定义标题描述和宽度:

public class ExtendedListView : ListView
{
    public static readonly DependencyProperty AutoColumnsProperty =
               DependencyProperty.Register("AutoColumns", typeof(bool), typeof(ExtendedListView), new FrameworkPropertyMetadata(true, OnAutoColumnsPropertyChanged));

    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);

        OnAutoColumnsPropertyChanged(this, new DependencyPropertyChangedEventArgs(AutoColumnsProperty, false, true));
    }

    private static void OnAutoColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var newValue = (bool)e.NewValue;

        var dataGrid = (ExtendedListView)d;

        if (newValue)
        {
            dataGrid.AddAutoColumns();
        }
        else
        {
            dataGrid.DeleteAutoColumns();
        }           
    }

    Type GetBaseTypeOfEnumerable(IEnumerable enumerable)
    {
        if (enumerable == null)
        {
            return null;                
        }

        var genericEnumerableInterface = enumerable
            .GetType()
            .GetInterfaces().FirstOrDefault(i => i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

        if (genericEnumerableInterface == null)
        {
            return null;
        }

        var elementType = genericEnumerableInterface.GetGenericArguments()[0];

        if (!elementType.IsGenericType)
        {
            return elementType;
        }

        return elementType.GetGenericTypeDefinition() == typeof(Nullable<>)
            ? elementType.GetGenericArguments()[0]
            : elementType;
    }

    private readonly HashSet<GridViewColumn> autoGeneratedColumns = new HashSet<GridViewColumn>();

    private void AddAutoColumns()
    {
        var gridView = View as GridView;

        if (gridView == null)
        {
            throw new Exception("Not a grid view");
        }

        var itemType = GetBaseTypeOfEnumerable(ItemsSource);

        if (itemType == null)
        {
            throw new Exception("Could not resolve item type");
        }

        var properties = itemType.GetProperties();
        foreach (var property in properties)
        {
            var gridViewColumn = new GridViewColumn
            {
                CellTemplate = CreateTemplate(property.Name),
                Header = property.Name,
                Width = 100
            };

            gridView.Columns.Add(gridViewColumn);

            autoGeneratedColumns.Add(gridViewColumn);
        }           
    }

    private DataTemplate CreateTemplate(string path)
    {
        string xamlTemplate = string.Format("<DataTemplate><ContentPresenter Content=\"{{Binding {0}}}\" ContentTemplate=\"{{StaticResource GridViewTextCell}}\" /></DataTemplate>", path);

        var context = new ParserContext
        {
            XamlTypeMapper = new XamlTypeMapper(new string[0])
        };

        context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
        context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

        var template = (DataTemplate)XamlReader.Parse(xamlTemplate, context);

        return template;
    }

    private void DeleteAutoColumns()
    {
        var gridView = View as GridView;

        if (gridView == null)
        {
            throw new Exception("Not a grid view");
        }

        for (int columnIndex = gridView.Columns.Count - 1; columnIndex >= 0; --columnIndex)
        {
            if (autoGeneratedColumns.Contains(gridView.Columns[columnIndex]))
            {
                gridView.Columns.RemoveAt(columnIndex);
            }
        }       
    }

    public bool AutoColumns
    {
        get { return (bool)GetValue(AutoColumnsProperty); }
        set { SetValue(AutoColumnsProperty, value); }
    }
}

【讨论】:

    猜你喜欢
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2021-10-02
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    相关资源
    最近更新 更多