15


3

次のような問題があります。

https://stackoverflow.com/questions/983272/silverlight-datagridtextcolumn-binding-visibility[Silverlight DataGridTextColumn Binding Visibility]

Silverlight DataGrid内の列をViewModel内の値に基づいて表示/縮小する必要があります。 これを実現するために、VisibilityプロパティをViewModelにバインドしようとしています。 しかし、私はすぐにVisibilityプロパティがDependencyPropertyではないことを発見しました。したがって、バインドすることはできません。

これを解決するために、私は自分のDataGridTextColumnをサブクラス化しようとしました。 この新しいクラスを使用して、最終的にはDataGridTextColumn.Visibilityプロパティへの変更をプッシュするDependencyPropertyを作成しました。 データバインドしていない場合、これはうまく機能します。 新しいプロパティにデータバインドすると、AG_E_PARSER_BAD_PROPERTY_VALUE例外で失敗します。

パブリッククラスMyDataGridTextColumn:DataGridTextColumn {#region public Visibility MyVisibility

public static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register( "MyVisibility"、typeof(表示設定)、typeof(MyDataGridTextColumn)、新しいPropertyMetadata(表示設定.Visible、OnMyVisibilityPropertyChanged))

OnMyVisibilityPropertyChanged(DependencyObject d、DependencyPropertyChangedEventArgs e){var @this = dはMyDataGridTextColumnです。

if(@this!= null){@ this.OnMyVisibilityChanged((Visibility)e.OldValue、(Visibility)e.NewValue); }}

private void OnMyVisibilityChanged(Visibility oldValue、Visibility newValue){Visibility = newValue; }

public Visibility MyVisibility {get {return(Visibility)GetValue(MyVisibilityProperty);} set {SetValue(MyVisibilityProperty、value);} }}

#endregion public Visibility MyVisibility}

これがXAMLの小さな断片です。


*いくつかの重要な事実

  • Converterは実際にはローカルリソースで上記で定義されています。

  • コンバータは正しいです、それはソリューションの他の多くの場所で使用されています。

  • MyVisibilityプロパティの\ {Binding}構文を "Collapsed"に置き換えると、列は実際には消えます。

  • 新しいDependencyPropertyを作成した場合 文字列Foo)にバインドし、それにバインドしてもAG_E_PARSER_BAD_PROPERTY_VALUE例外が発生します。

なぜこれがうまくいかないのかについて誰かが何か考えを持っていますか?

9 Answer


7


これが私がちょっとしたハックを使って思いついた解決策です。

まず、DataGridから継承する必要があります。

パブリッククラスDataGridEx:DataGrid {public IEnumerable HiddenColumns {get {return(IEnumerable)GetValue(HiddenColumnsProperty);} set {SetValue(HiddenColumnsProperty、value);} }}

public static readonly DependencyProperty HiddenColumnsProperty = DependencyProperty.Register( "HiddenColumns"、typeof(IEnumerable)、typeof(DataGridEx)、新しいPropertyMetadata(HiddenColumnsChanged));

プライベートstatic void HiddenColumnsChanged(オブジェクト送信側、DependencyPropertyChangedEventArgs引数){var dg = DataGridとして送信側。 if(dg == null || args.NewValue == args.OldValue)

var hiddenColumns =(IEnumerable)args.NewValue; foreach(dg.Columnsのvar列){if(hiddenColumns.Contains((文字列)column.GetValue(NameProperty)))column.Visibility = Visibility.Collapsed;それ以外の場合はcolumn.Visibility = Visibility.Visible; }}}
  • DataGridEx クラスは、 DataGridColumn およびその子孫の x:Name *に基づいて列を非表示にするための新しいDPを追加します。

XAMLで使用するには

Header = "Count" Binding = {Binding CountOfItems} "

あなたはあなたのViewModelまたはあなたが使うどんなデータコンテキストにでもこれらを追加する必要があります。

private IEnumerable _hiddenColumns; public IEnumerable HiddenColumns {get {return _hiddenColumns;}プライベートセット{if(value == _hiddenColumns)が返されます。

_hiddenColumns = value; PropertyChanged(これ、新しいPropertyChangedEventArgs( "HiddenColumns")); }}

public void SomeWhereInYourCode(){HiddenColumns = new List {"uiDataCountOfItems"}; }

表示するには、リストから対応する名前を削除するか、表示されていない名前を付けずに再作成するだけです。


6


私はあなたがDataGridTextColumnで見つける "Binding"プロパティに似たアプローチを使うこの問題に対する別の解決策を持っています。 列クラスはDependencyObjectsなので、それらに直接データバインドすることはできません。ただし、INotifyPropertyChangedを実装するFrameworkElementへの参照を追加する場合は、データバインディングを要素に渡して、依存関係プロパティを使用してColumnデータバインディングが変更されました。

注目すべき1つのことは、グリッドではなく列自体にバインディングを設定するということは、おそらくhttp://weblogs.asp.net/dwahlin/archive/2009/08/20 / create-aを使用したいということになるということです。 Visibilityをバインドするフィールドへのアクセスを取得するには、-silverlight-datacontext-proxy-nested-controls.aspx [DataContextProxy]を使用します(列のバインドは、デフォルトではItemSource)。

システムを使用する。 System.ComponentModelを使用します。 System.Windowsを使用します。 System.Windows.Controlsを使用します。 System.Windows.Dataを使用します。

名前空間XYZ.Controls {public class ExtendedDataGridTextColumn:DataGridTextColumn {private読み取り専用Notifier _e;}

プライベートバインディング_visibilityBinding; public Binding VisibilityBinding {get {return _visibilityBinding;}} } {_visibilityBinding = value;}を設定します。 _e.SetBinding(Notifier.MyVisibilityProperty、_visibilityBinding); }}

public ExtendedDataGridTextColumn(){_e = new Notifier();} _e.PropertyChanged = ToggleVisibility; }

private void ToggleVisibility(オブジェクト送信側、PropertyChangedEventArgs e){if(e.PropertyName == "Visibility")this.Visibility = _e.MyVisibility; }

// Notifierクラスは、プロパティ変更イベントを列コンテナのDependency Objectに返すために使用されています。これは、現在はプライベートクラスNotifierのプライベート内部クラスとして残します。

public Visibility MyVisibility {get {return(Visibility)GetValue(MyVisibilityProperty);}プライベートセット{SetValue(MyVisibilityProperty、value);} }}

public static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register( "MyVisibility"、typeof(Visibility)、typeof(Notifier)、新しいPropertyMetadata(MyVisibilityChanged));

プライベート静的無効MyVisibilityChanged(DependencyObject d、DependencyPropertyChangedEventArgs e){Notifierとしてvar n = d。 if(n!= null){n.MyVisibility =(可視性)e.NewValue; n.PropertyChanged(n、new PropertyChangedEventArgs( "Visibility")); }}}}

}


3


datagrid列はFrameworkElementではなくDependencyObjectから継承します。 WPFではこれは大したことではありません…​ しかしSilverlightでは、FrameworkElementオブジェクトにしかバインドできません。 試してみると、AG_E_PARSER_BAD_PROPERTY_VALUEというエラーメッセージが表示されます。


2


これがどの程度役立つかはわかりませんが、私の最新プロジェクトでは、データグリッド列に関する依存関係プロパティの問題が発生しています。 これを回避するために行ったことは、グリッド列ビューモデルでイベントを作成し、次にクライアントでグリッドを組み立てるときにクロージャを使用してグリッド列を列ビューモデルにサブスクライブさせることでした。 私の特定の問題は幅の周りでした。 グリッド列のビューモデルクラスから始まります。これは次の擬似コードのようになります。

public delegate void ColumnResizedEvent(double width);

public class GridColumnViewModel : ViewModelBase
{
    public event ColumnResizedEvent ColumnResized;

    public void Resize(double newContainerWidth)
    {
        // some crazy custom sizing calculations -- don't ask...
        ResizeColumn(newWidth);
    }

    public void ResizeColumn(double width)
    {
        var handler = ColumnResized;
        if (handler != null)
            handler(width);
    }
}

それからグリッドを組み立てるコードがあります。

public class CustomGrid
{
    public CustomGrid(GridViewModel viewModel)
    {
        // some stuff that parses control metadata out of the view model.
        // viewModel.Columns is a collection of GridColumnViewModels from above.
        foreach(var column in viewModel.Columns)
        {
            var gridCol = new DataGridTextColumn( ... );
            column.ColumnResized  += delegate(double width) { gridCol.Width = new DataGridLength(width); };
        }
    }
}

データグリッドがアプリケーション内でサイズ変更されると、resizeイベントが拾われ、グリッドがバインドされているビューモデルのresizeメソッドを呼び出します。 これにより、各グリッド列ビューモデルのサイズ変更メソッドが呼び出されます。 次に、グリッド列ビューモデルは、データグリッドテキスト列がサブスクライブされる `+ ColumnResized +`イベントを発生させ、その幅が更新されます。

これはあなたの問題を直接解決するものではないことを私は認識していますが、依存性がない場合はビューモデルをデータグリッドの列に "バインド"できる方法でした。 クロージャーは、私が望んでいた振る舞いをうまくカプセル化した単純な構成で、私の後ろにいる誰かには非常に理解しやすいものです。 視界の変化に対処するためにそれをどのように変更できるかを想像するのはそれほど難しくないと思います。 イベントハンドラをページ/ユーザーコントロールのloadイベントに結び付けることもできます。


1


クリスマンシーニ、

データグリッド列の "Binding"プロパティへのバインディングは作成しません。 さて、あなたは "\ {Binding User.UserName}"と書きますが、(zacharyが言ったように)datagridカラムはFrameworkElementを継承しておらず、SetBindingメソッドを持っていないので、バインディングを作成しません。 そのため、式 "\ {Binding User.UserName}"は単にBindingオブジェクトを作成し、それを列のBindingプロパティに割り当てます(このプロパティはBindingの型です)。 次に、datagrid列はセルの内容を生成しながら(GenerateElement - protectedメソッド)、生成された要素にバインディングを設定するためにこのBindingオブジェクトを使用します(例: FrameworkElementsである生成TextBlockのTextプロパティに


1


GreatTall1のソリューションは素晴らしいですが、動作させるには少し変更する必要があります。

Notifierとしてvar n = d。 if(n!= null){//コールバックに値を代入するとバインディングが解除されます。 //n.MyVisibility =(Visibility)e.NewValue; n.PropertyChanged(n、new PropertyChangedEventArgs( "Visibility")); }


1


この問題は、「可視性」が依存関係プロパティではないほど単純ではないことに注意してください。 DataGridでは、列は視覚的な「ツリー」の一部ではないため、WPF(またはSilverlight 5)でもAncestorTypeを使用できません。

ここにWPF関連のリンクがいくつかあります(Silverlightでこれらの作品のいずれかがあればコメントしてください - 申し訳ありませんが、今テストする時間がありません)。

特定の解決策(および巧妙な解決策)の問題点と失敗についての非常に優れた説明があります。データ・コンテキストは継承されない/

そして、StackOverflowのカップルがいくつか質問します。

https://stackoverflow.com/questions/2518484/wpf-hide-datagridcolumn-via-a-binding[WPFバインディングを介してDataGridColumnを非表示にする]

https://stackoverflow.com/questions/669060/binding-to-visible-property-datagridcolumn-in-wpf-datagrid


1


これはデータグリッドテンプレート列に対して機能します。

ExtendedDataGridColumn:DataGridTemplateColumn {public static readonly} DependencyProperty VisibilityProperty = DependencyProperty.Register( "Visibility"、typeof(Visibility)、typeof(DataGridTemplateColumn)、new PropertyMetadata(Visibility.Visible、VisibilityChanged)); public new Visibility Visibility {get {return(Visibility)GetValue(VisibilityProperty); set {SetValue(VisibilityProperty、value);} VisibilityChanged(DependencyObject d、DependencyPropertyChangedEventArgs e){if((DataGridTemplateColumn)d!= null){(((DataGridTemplateColumn)d)).Visibility =(Visibility)e.NewValue;}} }}}


0


MyDataGridTextColumnクラスから、周囲のDataGridを取得できます。 その後、DataGridのDataContextからViewModelを取り出し、ViewModelのPropertyChangedイベントにハンドラを追加します。 ハンドラーでは、プロパティ名とその値を確認し、それに応じて列の表示設定を変更するだけです。 これは最善の解決策ではありませんが、うまくいくはずです。