4

ListViewのビューとして設定されているGridView内の「セル」のテキスト値を取得しようとしています。ListViewのSelectedItemを取得したくありません。これは、ビューモデル全体を返すだけです(ただし、セルが参照するプロパティは返しません)。

マウスの直接イベント(上下など)に応答することでテキスト値を取得できます。値がテキストブロックの場合は、明らかにテキストを使用できます。これはうまく機能し、現時点ではこれが私の唯一の解決策ですが、現在は制限されています。

さらに一歩進んで、セル領域内の任意の場所をクリックし、ナビゲートして適切なテキストブロックを見つけ、その値を使用できるようにしたいと思います。私はこれを行うために50万の方法を試しましたが、論理的に見えることは、本来のようにうまく機能していないようです。

設定:

渡したデータモデルに基づいて独自の列とバインディングを作成する動的GridViewがあります。プログラムによるセルテンプレート(以下に表示)を使用して、セルを個別に制御しています。特に、セルに「境界線」を追加して、実際に各セルを分離できるようにしています。VisualTree内を移動するときにオブジェクトに簡単にアクセスできるように、オブジェクトに名前を付けました。

これがテンプレートコードです。(コンテンツプレゼンターは元々テキストブロック自体でしたが、後で柔軟性を持たせるために変更されていることに注意してください)

private DataTemplate GetCellTemplate(string bindingName)
    {
        StringBuilder builder = new StringBuilder();
        builder.Append("<DataTemplate ");
        builder.Append("xmlns='http://schemas.microsoft.com/winfx/");
        builder.Append("2006/xaml/presentation' ");
        builder.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
        builder.Append("xmlns:local = 'clr-namespace:XXXXXXXX");
        builder.Append(";assembly=XXXXXXXXX'>");
        builder.Append("<Border Name=\"border\" BorderThickness=\"1,0,0,0\" BorderBrush=\"Gray\" Margin=\"-6,-3,-6,-3\">");
        builder.Append("<Grid Margin=\"6,3,6,3\">");
        builder.Append("<ContentPresenter Name=\"content\" HorizontalAlignment=\"Stretch\" Content=\"{Binding ");
        builder.Append(string.Format("{0}", bindingName));
        builder.Append("}\"/>");
        builder.Append("</Grid>");
        builder.Append("</Border>");
        builder.Append("</DataTemplate>");
        DataTemplate cellTemplate= (DataTemplate)XamlReader.Parse(builder.ToString());
        return cellTemplate; 
    }

私が試したこと:

私にとっての論理的なアプローチは、Mouseイベントに反応することでした。マウスイベントが発生したオブジェクトから、A。子を調べてテキストブロックを見つけるか、B。親を取得してから、テキストブロックを持つ子を探します。

私の仮定は、空白をクリックすると、テキストブロックのあるコンテナをクリックしているということです。これまでのところ、表示される2つのものは、境界線と長方形です(テキスト自体をクリックしない場合)。A.リアングルとボーダー以外は何も返しません。Bを実行すると、テキストブロックを見つけることができますが、それらは行全体のすべてのテキストブロックです。

したがって、そこから実行しようとしているのは、すべてのテキストブロックを取得してから、IsMouseOverプロパティがtrueであることがわかるまで逆方向に移動することです。行全体のコンテンツプレゼンターを除いて、これらのオブジェクトのいずれにもIsMouseOverがないことがわかります。したがって、これは、セル内の空白に実際にはテキストブロックが含まれていないことを示しているようです。

私が見つけたのは、境界線をクリックして子を見始めると、最終的に長方形(クリックした長方形)とグリッド行ビュープレゼンターを持つコンテナーに到達することです。プレゼンターは、行内のすべてのオブジェクトを表示します(したがって、この再帰スキャンを実行すると、すべてのテキストブロックが取得されるのはなぜですか)。

これは、私が何をしているのかを理解するためにこれを行うために使用されるコードの一部です。私は、この同じ再帰コードの約10の異なるバージョンを作成しました。一般的に、マウスをその上に置き、テキストボックスに関連しているユーザーを見つけようとしています。

private void OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        object original = e.OriginalSource;
        if (original is TextBlock)
        {
            this.valueTextBlock.Text = ((TextBlock)original).Text;
        }
        else if (original is FrameworkElement)
        {
            var result = GetAllNestedChildren<Border>(VisualTreeHelper.GetParent((DependencyObject)original)).Where(x => x.Name == "border").Where(x => HasAChildWithMouse(x)).ToList();

        }
        else
        {
            this.valueTextBlock.Text = string.Empty;
        }
    }

    private bool HasAChildWithMouse(UIElement element)
    {
        if (element.IsMouseOver || element.IsMouseDirectlyOver)
            return true;
        var childCount = VisualTreeHelper.GetChildrenCount(element);
        for (int i = 0; i < childCount; ++i)
        {
            var child = VisualTreeHelper.GetChild(element, i);
            if (child is UIElement)
                if (HasAChildWithMouse((UIElement)child))
                    return true;
        }
        return false;
    }
private IEnumerable<T> GetAllNestedChildren<T>(DependencyObject obj) where T : UIElement
    {
        if (obj is T)
            yield return obj as T;
        var childCount = VisualTreeHelper.GetChildrenCount(obj);
        for (int i = 0; i < childCount; ++i)
        {
            var child = VisualTreeHelper.GetChild(obj, i);
            foreach (var nested in GetAllNestedChildren<T>(child))
                yield return nested; 
        }
    }

    private T GetObjectByTypeParentHasMouse<T>(DependencyObject obj) where T : UIElement
    {
        if (obj is T)
        {
            if ((VisualTreeHelper.GetParent(obj) as UIElement).IsMouseOver )
            {
                return obj as T;
            }
        }
        var childCount = VisualTreeHelper.GetChildrenCount(obj);
        for (int i = 0; i < childCount; ++i)
        {
            var child = VisualTreeHelper.GetChild(obj, i);
            var correctType = GetObjectByTypeParentHasMouse<T>(child);
            if (correctType != null)
                return correctType;
        }
        return null;
    }

    private T GetContainedType<T>(DependencyObject obj, bool checkForMouseOver) where T : UIElement 
    {
        if (obj is T && ((T)obj).IsMouseOver)
            return obj as T;
        var childCount = VisualTreeHelper.GetChildrenCount(obj);
        for (int i = 0; i < childCount; ++i)
        {
            var child = VisualTreeHelper.GetChild(obj, i);
            var correctType = GetContainedType<T>(child, checkForMouseOver);
            if (correctType != null)
                return correctType;
        }
        return null;
    }

私が取ったもう1つのアプローチは、TextBlock自体から始めて、それに含まれる親を見つけ、答えに移動する方法を見つけることでした。templateparentはContentPresenter(= "content"という名前)であることがわかりました。グリッド、次に境界線が見つかりました。境界線の親はコンテンツプレゼンターであり、そのコンテンツは行全体のデータビューモデルです。このコンテンツプレゼンターの親は、グリッド列のプレゼンターです。これは私が他のものでナビゲートしていたものと同じものです。

セルが含まれている間の最初のアプローチオブジェクトには、実際にはテキストブロックまたはセルのテンプレートアイテム全体が含まれていないように見えます。クリックされた境界線または長方形から実際のテキストフィールドに戻る方法はないように思われます。

「短編小説」このつながりを作る方法はありますか?

(ところで、このListView / GridViewの見返りはこのマイナスをはるかに上回っているため、私はこのListView / GridViewをあきらめたくありません。残りを維持するために、このアイデアをあきらめたいと思います)。

4

1 に答える 1

0

私はあなたができるはずだと思います

1) ある種の (トグル) ボタンをデータ テンプレートのルートに追加し、Command にバインドしてビューモデルで処理するか、IsChecked/IsPressed にバインドしてデータ トリガーまたはビュー側で変更を処理します。

2) ある時点で EventTrigger をデータ テンプレートに追加し、PreviewNouseUp/Down イベントを単純なアニメーションで処理します。

于 2013-02-06T11:01:06.667 に答える