在动态TabPage上绑定DataGrid的属性(宽/排序) [英] Binding properties (width/sorting) of DataGrid on dynamic TabPage

查看:117
本文介绍了在动态TabPage上绑定DataGrid的属性(宽/排序)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个小的wpf测试项目来演示我的问题。该项目包含一个单一的wpf窗口。此窗口只包含一个 TabControl TabControl 的页面是从绑定的 ItemSource 动态创建的。

I've created a little wpf test project to demonstrate my question. This project contains a single wpf window. This window contains only a TabControl. The pages of this TabControl are created dynamically from the bound ItemSource.

所以这里是我的xaml:

So here is my xaml:

<Window x:Name="window" x:Class="TestWpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:TestWpf"
    Title="MainWindow" Height="350" Width="525">
    <TabControl x:Name="tabControl" BorderThickness="0" ItemsSource ="{Binding MediaLists, ElementName=window, NotifyOnSourceUpdated=True}">
        <TabControl.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:MediaList}">
                <TextBlock Padding="2" Text="{Binding MediaTypeName}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate x:Name="contentTemplate" DataType="{x:Type vm:MediaList}">
                <DataGrid x:Name="dgMediaList" ItemsSource="{Binding Medias, BindsDirectlyToSource=True}" DockPanel.Dock="Top" AutoGenerateColumns="False" HorizontalGridLinesBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" VerticalGridLinesBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
                    <DataGrid.Columns>
                        <DataGridTextColumn x:Name="clmAuthor" Header="Author" Binding="{Binding Author}" IsReadOnly="True" CanUserReorder="False" />
                    <DataGridTextColumn x:Name="clmTitle" Header="Title" Binding="{Binding Title}" IsReadOnly="True" CanUserReorder="False" />
                    </DataGrid.Columns>
                </DataGrid>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Window>

后面的代码是这样的:

public partial class MainWindow : Window
{
    private readonly ObservableCollection<MediaList> m_MediaLists = new ObservableCollection<MediaList>();
    public ObservableCollection<MediaList> MediaLists { get { return m_MediaLists; } } 
    public MainWindow()
    {
        InitializeComponent();
        MediaList cdList = new MediaList("CDs");
        cdList.Medias.Add(new Media("AuthorCdA", "TitleCdA1"));
        cdList.Medias.Add(new Media("AuthorCdA", "TitleCdA2"));
        cdList.Medias.Add(new Media("AuthorCdB", "TitleCdB1"));
        cdList.Medias.Add(new Media("AuthorCdB", "TitleCdB2"));

        MediaList bookList = new MediaList("Books");
        bookList.Medias.Add(new Media("AuthorBookA", "TitleBookA1"));
        bookList.Medias.Add(new Media("AuthorBookA", "TitleBookA2"));
        bookList.Medias.Add(new Media("AuthorBookB", "TitleBookB1"));
        bookList.Medias.Add(new Media("AuthorBookB", "TitleBookB2"));

        m_MediaLists.Add(cdList);
        m_MediaLists.Add(bookList);
    }
}

MediaList 如下:

public class MediaList : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private readonly ObservableCollection<Media> m_Medias = new ObservableCollection<Media>(); 
    public string MediaTypeName { get; private set; }
    public ObservableCollection<Media> Medias { get { return m_Medias; }}

    public MediaList(string typeName)
    {
        MediaTypeName = typeName;
    }
}

媒体这样:

public class Media
{
    public string Author { get; private set; }
    public string Title { get; private set; }
    public Media(string author, string title)
    {
        Author = author;
        Title = title;
    }
}

所以这一切都可以正常工作,你可以在这里看到:

So this all works fine as you can see here:

现在问题是:如何为每个 TabPage 保存 DataGrid 的布局当我在 TabPage s,所有页面的列宽保持不变,但排序总是完全丢失。

Now the problem: is how to save the DataGrid's layout for each TabPage? When I switch between the TabPages, the column width are kept the same for all pages, but the sorting is always lost completely.

我想绑定 DataGrid 的列宽以及多列排序设置,由用户在 MediaList 实例

I want to bind the column widths of the DataGrid as well as the multi-column sort settings as changed by the user in members of the MediaList instance.

所以为了保持这个问题的简短,让我们专注于列的宽度。我将成员添加到 MediaList 类中:

So to keep this question short, let's concentrate on the column widths. I added the members to the MediaList class:

private DataGridLength m_WidthAuthor = DataGridLength.SizeToCells;
private DataGridLength m_WidthTitle = DataGridLength.SizeToCells;
public DataGridLength WidthAuthor
{
    get { return m_WidthAuthor; }
    set
    {
        if (value == m_WidthAuthor) return;
        m_WidthAuthor = value;
        OnPropertyChanged("WidthAuthor");
    }
}
public DataGridLength WidthTitle
{
    get { return m_WidthTitle; }
    set
    {
        if (value == m_WidthTitle) return;
        m_WidthTitle = value;
        OnPropertyChanged("WidthTitle");
    }
}

并尝试在xaml中设置绑定: / p>

and tried to set the binding in the xaml:

<DataGridTextColumn x:Name="clmAuthor" ... Width="{Binding WidthAuthor, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn x:Name="clmTitle" ... Width="{Binding WidthTitle, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" />

但不幸的是,这不行。我已经阅读了几篇SO文章,双向约束将是困难的。但即使是单向约束也不适用于我。 (我很新的wpf / mvvm,所以也许我在这里使用一些错误的单词

But unfortunatly, this doesn't work. I've read on several SO articles that a two-way binding would be difficult. But even one-way binding won't work for me. (I'm pretty new to wpf/mvvm, so maybe I use some wrong words here...)

在调试器的输出窗口我可以看到我的宽度绑定的这些错误信息:

In the debugger output window I can see these error message for my width-bindings:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=WidthAuthor; DataItem=null; target element is 'DataGridTextColumn' (HashCode=54916642); target property is 'Width' (type 'DataGridLength')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=WidthTitle; DataItem=null; target element is 'DataGridTextColumn' (HashCode=40809782); target property is 'Width' (type 'DataGridLength')

所以如果有人可以告诉我如何保存那些 DataGrid 属性为每个 TabPage 我会很开心。这个问题的重点在于宽度。排序可能是一个新问题(请注意,绑定列的 SortDirection 可能不适用于多列排序)

So if anyone can tell me how to save those DataGrid properties for each TabPage I would be very happy. Focus of this question is on the widths. The sorting may be subject of a new question (note that binding the SortDirection of the columns probably won't work for multi-column sort)

编辑:我已将 diag:PresentationTraceSources.TraceLevel = High 添加到 / code>表达式到其中一列宽度,并在调试输出中找到这些消息:

I've added diag:PresentationTraceSources.TraceLevel=High to the Binding expression to one of the columns Width and found these messages in the debug output:

System.Windows.Data Warning: 62 : BindingExpression (hash=18270086): Attach to System.Windows.Controls.DataGridTextColumn.Width (hash=37671782)
System.Windows.Data Warning: 64 : BindingExpression (hash=18270086): Use Framework mentor <null>
System.Windows.Data Warning: 67 : BindingExpression (hash=18270086): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=18270086): Framework mentor not found
System.Windows.Data Warning: 65 : BindingExpression (hash=18270086): Resolve source deferred

对于wpf来说,太新鲜了,这个框架导师是什么,如果这应该是 null

I'm too new to wpf to understand what that Framework mentor is and if this should really be null.

推荐答案

我在这篇文章。不幸的是,我的wpf知识仍然很低,我无法解释(以及上述文章的作者)幕后发生了什么,如果这真的是一个很好的解决方案。

I solved it with the help of this article. Unfortunately my wpf knowledge is still so low that I cannot explain (as well as the author of the mentioned article) what happens behind the scenes and if this is really a good solution.

所以这里是我所做的:

的问题是 DataContext 不会继承到 DataGridTextColumn 。所以目的是将它存储在代理中。

One of the problems is that the DataContext is not inherited to DataGridTextColumn. So the aim is to store it in a proxy.

public class BindingProxy : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    public object Data
    {
        get { return GetValue(DATA_PROPERTY); }
        set { SetValue(DATA_PROPERTY, value); }
    }

    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DATA_PROPERTY =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}



在DataGrid中声明BindingProxy作为本地资源的实例< h3>

我将这个本地资源添加到我的 DataGrid 在xaml中:

<DataGrid.Resources>
    <vm:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>



调整绑定



最后我修改 DataGridTextColum 的宽度的绑定表达式:

Adjusting the binding

At last I modify the binding expression for the DataGridTextColum's width:

Width="{Binding Data.WidthAuthor, Source={StaticResource proxy}....

etvoilá,it作品!

et voilá, it works!

我将继续研究如何为多列排序,如果我找不到解决方案,我会打开一个新的问题。如果没有人在接下来的日子里添加一个解决方案,我会接受我自己的回答。

I will continue research on how to do this for the multi-column sort. If I can't find a solution to that I will open a new question. If no one adds a solution for that in the next days, I will accept my own answer.

更新:我解决了多列排序问题此处

UPDATE: I solved the multi-column sort problem here.

这篇关于在动态TabPage上绑定DataGrid的属性(宽/排序)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆