1

ユーザーがリモートサーバーに送信される数字のグリッドを貼り付けることができる UI アプリを作成しています。クライアントは WPF または Silverlight です。

文字列内のタブ区切りの行からコントロールに変換して、ユーザーの貼り付け入力をフックするためにGrid使用するTextboxコントロールを試しました。ユーザーが Excel からわずか 122x161 のセルを貼り付けた後、これが更新されるまでに 12 秒 (!) かかりますが、これは容認できないほど遅いです。文字列の分析には 0.1 秒、行と列の追加には 1 秒、コントロールの作成と挿入には 2 秒かかり、残りの 12 秒は最初のコントロールの描画に費やされたようです。DataObject.AddPastingHandlerTextboxTextBoxTextBox

私も試してみましDataGridたが、リフレクションを使用してプロパティを分析するオブジェクトの 1D 配列を優先して、2D 配列をうまく処理していないようです。

今、私は a を使ってCanvas自分で数字を描くことを考えていますが、それは正気ではないようです。組み込みの WPF または Silverlight コントロールを使用して、ユーザーに苦痛を与えることなくこれを行う簡単な方法はありますか?

編集

TextBoxそれ以来、めちゃくちゃ遅いので、私は犯人として特定しました。問題を示すいくつかの F# コードを次に示します ( を に置き換えるTextBoxTextBlock、40 倍高速になります。これは、本来よりも桁違いに遅くなりますが、このインスタンスでは許容されます)。

open System.Windows

let app = Application()

let readClipboard() =
  let data = (Clipboard.GetData "Text") :?> string
  [|for row in data.Split[|'\n'|] do
    match row.Split[|'\t'|] with
    | [||] | [|""|] -> ()
    | row -> yield row|]

[<System.STAThreadAttribute>]
do
  let grid = Controls.Grid()
  let row = Controls.RowDefinition()
  Controls.RowDefinition() |> grid.RowDefinitions.Add
  Controls.ColumnDefinition() |> grid.ColumnDefinitions.Add
  let add i j ctrl =
    Controls.Grid.SetRow(ctrl, i)
    Controls.Grid.SetColumn(ctrl, j)
    grid.Children.Add ctrl |> ignore
  let paste() =
    let timer = System.Diagnostics.Stopwatch.StartNew()
    let data = readClipboard()
    printfn "Read clipboard %fs" timer.Elapsed.TotalSeconds
    let rows = data.Length
    let cols = data |> Array.fold (fun n xs -> xs.Length |> max n) 0
    printfn "%dx%d" rows cols
    grid.RowDefinitions.Clear()
    grid.ColumnDefinitions.Clear()
    grid.Children.Clear()
    for row in 1..rows do
      Controls.RowDefinition(Height=GridLength 24.0) |> grid.RowDefinitions.Add
    for col in 1..cols do
      Controls.ColumnDefinition(Width=GridLength 64.0) |> grid.ColumnDefinitions.Add
    printfn "Add rows and columns complete %fs" timer.Elapsed.TotalSeconds
    for i in 0..rows-1 do
      for j in 0..data.[i].Length-1 do
        Controls.TextBox(Text=data.[i].[j]) |> add i j
    printfn "Insert complete %fs" timer.Elapsed.TotalSeconds
    Media.CompositionTarget.Rendering.Add(fun _ ->
      printfn "Next Rendering event at %fs" timer.Elapsed.TotalSeconds
      app.Shutdown())
  let scroll = Controls.ScrollViewer(Content=grid)
  scroll.HorizontalScrollBarVisibility <- Controls.ScrollBarVisibility.Visible
  let window = Window(Content=scroll)
  window.Focusable <- true
  window.Focus() |> ignore
  window.PreviewKeyDown.Add(fun e ->
    let ctrl = Input.ModifierKeys.Control
    if Input.Keyboard.Modifiers &&& ctrl = ctrl then
      if e.Key = Input.Key.V then
        paste())
  app.Run window |> ignore
4

2 に答える 2

0

コードビハインドを使用して列を追加するコードがいくつかあります。MVVMアプローチを使用している場合は理想的ではありませんが、パフォーマンスの問題には気づいていません(ただし、数百の列にプッシュしていません)。

以下のコードは、「参加者」を含むデータグリッドに「ブロック」列を追加するために使用されます。コンパイル時にブロックの数がわからないため、XAMLコード生成を使用してブロックを追加します。

public void AddParticipantGridViewColumns()
{
    var setupViewModel = (SetupPanelViewModel)DataContext;
    if (setupViewModel.BlockSlotViewModels == null) return;
    var blockColumnCount = setupViewModel.BlockSlotViewModels.Count();
    var dataGrid = (DataGrid)ParticipantDataGrid;
    if (dataGrid.Columns.Count == blockColumnCount + 1) return;
    for (var blockIndex = 0; blockIndex < blockColumnCount; blockIndex++)
    {
        var column = BuildParticipantGridViewColumn(blockIndex);
        dataGrid.Columns.Add(column);
    }
}

private DataGridTemplateColumn BuildParticipantGridViewColumn(int blockIndex)
{
    var columnXaml = string.Format(@"
        <DataGridTemplateColumn
            xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
            xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
            Header=""Block {1}"">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text=""{{Binding BlockSlotViewModels[{0}].ConditionLabel}}""
                               Foreground=""{{Binding BlockSlotViewModels[{0}].TextBrush}}"" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>",
        blockIndex, blockIndex + 1);
    var column = (DataGridTemplateColumn)XamlReader.Parse(columnXaml);
    return column;
}
于 2012-09-21T16:31:18.513 に答える
0

TextBox問題は、非常に遅い組み込みの WPF コントロールであることが判明しました。したがって、それを回避するか、交換する必要があります。

この場合、テキストが欲しかったので、TextBlock代わりに使用することで回避できます。これにより、セルを貼り付ける時間が 12 秒から 0.25 秒に短縮されます。これは (ほぼ) 許容範囲です。

編集可能なセルが必要な場合は、TextBlockどこでも使用して、編集中の 1 つのセルのみを に変換する必要TextBoxがあります。これは非常に遅いためです。

于 2012-09-22T10:48:31.780 に答える