Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
 Обсуждение подходов к установке свойства Visibility в колонках DataGrid-а  [new]
monstrilla
Member

Откуда:
Сообщений: 129
Наверное всем приходилось сталкиваться с ситуацией, когда нужно скрывать-показывать колонку в DataGrid-e. Многие знают, что колонка в гриде не является частью визуального дерева, посему не наследует DataContext окна, т.е. напрямую к свойству DataContext-a забиндиться нельзя. Так вот, как скрывать-показывать колонку я могу реализовать тремя способами, вопрос не в этом. Вопрос в том, как эти способы работают "внутри". Просто интересно разобраться. Третий способ (через x:Reference) неинтересный, предлагаю сравнить два. Разметка и код прилагаются.

XAML:

 <Window.Resources>
        <myNs:FreezableProxy x:Key="FreezableProxy" Data="{Binding}"/>
        <FrameworkElement x:Key="FrameworkElement"/>
    </Window.Resources>
        
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <DataGrid AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name"/>
                <DataGridTextColumn Header="Type" 
                                    Visibility="{Binding Data.IsPartnerColumnVisible, Source={StaticResource FreezableProxy}}"/>
                <DataGridTextColumn Header="Number" 
                                    Visibility="{Binding DataContext.IsPartnerColumnVisible, Source={StaticResource FrameworkElement}}"/>
    
            </DataGrid.Columns>
        </DataGrid>
        <ContentControl Grid.Row="1" Content="{StaticResource FrameworkElement}" Visibility="Collapsed"></ContentControl>
    
    </Grid>



Code-behind:

public class FreezableProxy : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new FreezableProxy();
        }
    
        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
    
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object),
                                            typeof(FreezableProxy));
    }

    public partial class MainWindow : INotifyPropertyChanged
    {
        private Visibility _isPartnerColumnVisible = Visibility.Hidden;
        public Visibility IsPartnerColumnVisible
        {
            get
            {
                return _isPartnerColumnVisible;
            }
            set
            {
                _isPartnerColumnVisible = value;
                RaisePropertyChanged("IsPartnerColumnVisible");
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        void RaisePropertyChanged(String prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }
    }


Оба подхода очень похожи, оба используют прокси-элемент в качестве ресурса. Разница только в типе. Рассмотрим первый подход через FreezableProxy. Как МНЕ видится как это работает. Создается класс, в классе определяется свойство зависимости (чтоб было куда биндить), потом в это свойство биндится DataContext окна, потом из этого свойства извлекается значение DataContext-a. Вроде все логично, вот только если создавать произвольный класс, а не наследник от Freezable, то работать не будет. Почему - непонятно. Вопрос! Буржуи пишут, что Freezable классы наследуют DataContext и фокус в этом. Вот только в классе Freezable нет свойства DataContext вообще как такового и так или иначе используется руками определенное свойство Data. При чем тут DataContext класса Freezable??? Вопрос!

Второй подход через FrameworkElement.

Буржуи пишут, что ContentControl наследует DataContext окна (согласен), FrameworkElement, в свою очередь, наследует DataContext у ContentControla (опять согласен). Таким образом, FrameworkElement имеет DataContext окна и потому строка


Binding DataContext.IsPartnerColumnVisible


правомерна. Тогда получается, что суть ContentControl-a - передавать транзитом DataContext окна FrameworkElemet-у. У меня возникает логичный вопрос, а почему сразу не написать так

<FrameworkElement x:Key="FrameworkElement" DataContext="{Binding}"/>


пробовал, не работает. Почему? Вопрос!
27 авг 14, 15:51    [16501885]     Ответить | Цитировать Сообщить модератору
 Re: Обсуждение подходов к установке свойства Visibility в колонках DataGrid-а  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13632
monstrilla
пробовал, не работает. Почему? Вопрос!
Вопрос из разряда "почему вода мокрая". Ну нужно искать смысл там, где его нет. Да никто и не обещал, что ресурсы будут наследовать DataContext.

Можно описать ViewModel в ресурсах и без проблем биндиться к ней напрямую через StaticResource.
     <Window.Resources>
        <my:ViewModel x:Key="viewModel"/>
     </Window.Resources>

    <DataGridTextColumn Visibility="{Binding IsPartnerColumnVisible, Source={StaticResource viewModel}}"/>

Если нужен именно DataContext, то можно попробовать ещё такой вариант:
<DataGridTextColumn Visibility="{Binding DataContext.IsPartnerColumnVisible, Source={DocumentRoot}}"/>
DocumentRootExtension
27 авг 14, 17:19    [16502639]     Ответить | Цитировать Сообщить модератору
 Re: Обсуждение подходов к установке свойства Visibility в колонках DataGrid-а  [new]
monstrilla
Member

Откуда:
Сообщений: 129
Алексей К,

нормальный вопрос :) я, кстати, разобрался, точнее мне таки объяснили буржуи

автор
Да никто и не обещал, что ресурсы будут наследовать DataContext.


угу, вот только я был не в курсе. Именно поэтому, ресурс типа Framework элемента нужно где-то размещать в визуальном дереве. ТОгда он понимает, что DataContext нужно наследовать. А Freezable класс хитро реализован и таки наследует DataContext, даже если НЕ является частью визуального дерева (на мсдн, кстати, про это ни слова). Если это принять как данность - вопросы отпадают.
27 авг 14, 17:46    [16502793]     Ответить | Цитировать Сообщить модератору
 Re: Обсуждение подходов к установке свойства Visibility в колонках DataGrid-а  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13632
monstrilla
А Freezable класс хитро реализован и таки наследует DataContext, даже если НЕ является частью визуального дерева (на мсдн, кстати, про это ни слова). Если это принять как данность - вопросы отпадают.
Тут
27 авг 14, 18:09    [16502941]     Ответить | Цитировать Сообщить модератору
Все форумы / WPF, Silverlight Ответить