[WPF] MVVMパターンにおいて、DataGridTextColumnがDataContextを参照する方法

#はじめに
WPF画面にて DataDrid を使っているとき、DataGridTextColumn の Visibilityプロパティが ItemsSource 外の ViewModel のメンバを参照したい場面が出てきました。
普通に、RelativeSource で記述しても、エラーとなり参照できません。

あれこれ調べていたら、[WPFの偉い人のブログ](http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/)の記事を参考に解決できましたので紹介します。

#環境
.NET Framework 4.6.1

#具体例

```csharp:ViewModel
public class ViewModel
{
    /// <summary>価格表示フラッグ</summary>
    public bool IsShowPrice { get; set; }

    /// <summary>データコレクション</summary>
    public List<Product> ProductList { get; set; }
}
```

こんな ViewModel を Window の DataContext に設定し、DataGrid は ProductList の一覧を表示。
そのとき、IsShowPrice が true のときだけ、Product 内にある Price 列を表示する・・・というケースです。

普通に考えると、

```xml:XAML
<DataGrid ItemsSource="{Binding ProductList}">
    <DataGrid.Columns>
        <!-- この列は、IsShowPriceがtrueのときだけ表示したい -->
        <DataGridTextColumn Header="Price"
                            Binding="{Binding Price}"
                            Visibility="{Binding DataContext.IsShowPrice,
                                Converter={StaticResource booleanToVisibilityConverter}}"/>
```

てな感じで動きそうですが、IsShowPrice の参照でエラーになっちゃいます。
RelativeSource での参照もうまく行きません。

```xml:これもエラーになります
Visibility="{Binding IsShowPrice, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
```

ItemsControl などで使う DataTemplate と異なり、DataGrid.Columns の子要素は、親（DataGrid）の仮想・論理ツリーに属していないから・・・というのが理由のようですが、なんのこっちゃ解りません。

#Freezable を使って解決
これを解決するには、[Freezableクラス](https://msdn.microsoft.com/en-us/library/system.windows.freezable.aspx)を継承した、データProxyオブジェクトを用意することで、参照可能になります。

まずはそのProxyクラスを作成します。

```csharp:BindingProxy.cs
public class BindingProxy : Freezable
{
    #region Overrides of Freezable
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
    #endregion

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

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


XAMLでは、DataGrid の Resource に、Window の DataContext への参照を定義します。

```xml:XAML
（略）
Proxyクラスへの名前空間を定義しておきます
xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
（略）

<DataGrid ItemsSource="{Binding ProductList}">
    <!-- DataContextのproxy -->
    <DataGrid.Resources>
        <vm:BindingProxy x:Key="proxy" Data="{Binding}"/>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Header="Price"
                            Binding="{Binding Price}"
                            Visibility="{Binding proxy.IsShowPrice,
                                Converter={StaticResource BooleanToVisibilityConverter}
                                Source={StaticResource proxy}}"/>
```

BindingProxy 定義のところで、`Data="{Binding}"` として、親（Window）のDataContextを対象にしています。
DataGridTextColumn の Visibilityでは、`Source={StaticResource proxy}` と記述することで、proxy.IsShowPrice メンバにアクセスできます。


#備考
この BindingProxy は、DataGrid.Columns だけでなく、ItemsControl などのコレクション要素でも使えます。
親要素を参照する RelativeSource の記述方法って、どうにもわかりづらいし、型をして上の階層を検索して・・・っていう動きがいまいち気に入らないです。
AncestorLevelを記述したら、入れ子構造に依存しまくりになるし。

そんな複雑な参照も、この BindingProxy なら、比較的シンプルに書けて見通しも良くなります。
ただし、双方向のバインディングは動かないので、グリグリ動くものには使えないですが。

#参考ページ

* [[WPF] HOW TO BIND TO DATA WHEN THE DATACONTEXT IS NOT INHERITED](http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/)