次のWPFサンプルプログラムがあります。
Xaml:
<Window x:Class="AncestorArie.MainWindow"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>
<Grid>
<DataGrid AutoGenerateColumns="False" Name="Blumen"
ItemsSource="{Binding Leaves}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Color}"
Header="Farbe" Width="160" />
<DataGridTextColumn Binding="{Binding Size}"
Header="Größe" Width="60"
Visibility="{Binding Path=DataContext.Flag,
RelativeSource={RelativeSource Findancestor,
AncestorType={x:Type Window}},
Converter={StaticResource BoolToVis}}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
背後にあるコード:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Flowers rose = new Flowers();
rose.Leaves = new ObservableCollection<Leaf>();
rose.Flag = false;
Leaf L1 = new Leaf();
L1.Color = "rot";
L1.Size = 3;
rose.Leaves.Add(L1);
Leaf L2 = new Leaf();
L2.Color = "gelb";
L2.Size = 2;
rose.Leaves.Add(L2);
this.DataContext = rose;
}
}
そして、モデルクラスは次のとおりです。
public class Leaf
{
public string Color { get; set; }
public int Size { get; set; }
}
public class Flowers
{
public bool Flag { get; set; }
public ObservableCollection<Leaf> Leaves { get; set; }
}
ご覧のとおり、Flag
プロパティがfalseに設定されている場合は、2番目のデータグリッド列を非表示にします。しかし、それは機能しません。 VisualStudioの[出力]ウィンドウで次のバインドエラーが発生します。
System.Windows.Dataエラー:4:参照 'RelativeSource FindAncestor、AncestorType =' System.Windows.Window '、AncestorLevel =' 1 ''でバインディングのソースが見つかりません。 BindingExpression:Path = DataContext.Flag; DataItem = null;ターゲット要素は 'DataGridTextColumn'(HashCode = 44856655);ターゲットプロパティは「Visibility」(タイプ「Visibility」)です
Visibility
属性に関するコードの何が問題になっていますか?
データグリッドの列は、ビジュアルツリーに表示されない抽象オブジェクトであるため、RelativeSource
-bindingを使用できません。また、ElementName
は、管理するFrameworkContentElementが見つからないため、機能しません。あなたは一種の束縛状態にあります。
動作する1つの方法は、Source
および x:Reference
、そのためには、ウィンドウに名前を付け、列をそのリソースに移動して、周期的な依存関係エラーを回避する必要があります。
<Window Name="_window" ...>
<Window.Resources>
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding Size}"
Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<!-- ... -->
<DataGrid AutoGenerateColumns="False" Name="Blumen"
ItemsSource="{Binding Leaves}">
<DataGrid.Columns>
<StaticResource ResourceKey="ThatPeskyColumn"/>
<!-- ... -->
とても楽しい。
Freezable
を使用するよりエレガントなアプローチをお勧めします。
<Window.Resources>
<DiscreteObjectKeyFrame x:Key="FlagKey" Value="{Binding Flag}"/>
</Window.Resources>
<DataGridTextColumn ... Visibility="{Binding Value, Source={StaticResource FlagKey}, ...}" />
DataGridTextColumnの可視性はDependencyPropertyではなく、データバインドできません。 DataGridTemplateColumnを使用して、テンプレート内のコントロールの可視性をバインドします。
編集:実際には、このステートメントはSilverlightにのみ適用されます。詳細については、この他のSOの質問を参照してください。
DataGridColumn.Visibilityをバインドする方法?
ここで、プロパティが依存関係であるかどうかを判断する最も簡単な方法について質問しました。
H.B.が提案したソリューション本当に優れており、真のWPFMVVM精神を持っています。可能な場合はそれを使用してください。
私の特定のケースでは、何かがうまくいかなかったので、私のプロジェクトは厳密なMVVMではないので、別の方法で出てきました。コード化されたソリューションを使用できます。
列に割り当てられたCustomView.xaml名:
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="MachinesColumn" ... />
...
CustomView.xaml.csには、列の可視性を直接変更する単純なプロパティがあります。
public Visibility MachinesColumnVisible
{
get { return MachinesColumn.Visibility; }
set
{
if (value == MachinesColumn.Visibility)
return;
MachinesColumn.Visibility = value;
}
}