简体   繁体   English

编辑源数据后更新/刷新列表框

[英]Update/Refesh Listbox after Editing Source Data

I would like to create in PowerShell a Windows form that uses a ListBox that selects data for editing.我想在 PowerShell 中创建一个 Windows 表单,该表单使用一个选择数据进行编辑的列表框。 As an entry in the ListBox is selected, textboxes below are bound to properties in the selected entry, allowing the editing of that entry.选择 ListBox 中的条目时,下面的文本框将绑定到所选条目中的属性,从而允许编辑该条目。 Sounds simple, and almost is, if only the ListBox would always show the current state of the data.听起来很简单,而且几乎就是这样,只要 ListBox 始终显示当前 state 的数据就好了。

A stripped down version of the code produces a form that looks like this image below.代码的精简版本生成如下图所示的表单。 The textboxes at the bottom of the form appear to work perfectly, that is, the test I've done show the bound data is changing as you type in them.表单底部的文本框似乎工作正常,也就是说,我所做的测试显示绑定数据在您输入时会发生变化。 But the content of the ListBox is never refreshed or updated, and so far all attempts at fixing this seem to either not work, cause other problems.但是 ListBox 的内容永远不会刷新或更新,到目前为止,所有修复此问题的尝试似乎要么不起作用,要么导致其他问题。

在此处输入图像描述

Initially I was creating a class in PowerShell for holding the data, but switched to a C# class:最初我在 PowerShell 中创建一个 class 来保存数据,但切换到 C# class:

Add-Type -ReferencedAssemblies "System.Windows.Forms" -Language CSharp -TypeDefinition @'
using System;
public class VectorData {
    double _degrees = 0.0d;
    double _distance = 0.0d;
    public double Degrees {
        get {
            return this._degrees;
        }
        set {
            this._degrees = value;
        }
    }
    public double Distance {
        get {
            return this._distance;
        }
        set {
            this._distance = value;
        }
    }
    public string Display {
        get {
            return "" + this._degrees + "\u00B0 \u2192 " + this._distance + "\u0027";
        }
    }
    public VectorData(double degrees, double distance){
        this._degrees = degrees;
        this._distance = distance;
    }
}
'@

I've tried all three of these examples for creating the list that can be bound to the ListBox, but none of them update the ListBox's content as the data changes.我已经尝试了所有这三个示例来创建可以绑定到 ListBox 的列表,但是当数据更改时,它们都没有更新 ListBox 的内容。

#$Vectors = [System.Collections.Generic.List[VectorData]]::new()
$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()
#$Vectors = [System.Collections.ObjectModel.ObservableCollection[VectorData]]::new()

This is the core code, $lbxVectors is the ListBox.这是核心代码,$lbxVectors 是 ListBox。 $tbxDegrees and $tbxDistance are textboxes. $tbxDegrees 和 $tbxDistance 是文本框。

function SetVectorsDataSource {
    $lbxVectors.DataSource = $null
    $lbxVectors.DataSource = $Vectors
    $lbxVectors.DisplayMember = 'Display'
}
function BindTextBoxes {
    $VD = $Vectors[$lbxVectors.SelectedIndex]
    $null = $txbDegrees.DataBindings.Clear()
    $null = $txbDegrees.DataBindings.Add('Text', $VD, "Degrees")
    $null = $txbDistance.DataBindings.Clear()
    $null = $txbDistance.DataBindings.Add('Text', $VD, "Distance")
}

$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))
SetVectorsDataSource
BindTextBoxes
$lbxVectors.Add_SelectedIndexChanged({
    BindTextBoxes
})

Calling the SetVectorsDataSource function from the textboxes' TextChanged event seems to overwrite what you type with the original data, so that doesn't work:从文本框的 TextChanged 事件调用 SetVectorsDataSource function 似乎会用原始数据覆盖您键入的内容,因此这不起作用:

$txbDegrees.Add_TextChanged({
#   SetVectorsDataSource
})
$txbDistance.Add_TextChanged({
#   SetVectorsDataSource
})

So, does anyone have any idea on how to keep the ListBox up-to-date with the current state of the data?那么,有没有人知道如何使 ListBox 与当前 state 的数据保持同步?

FYI: Here is the full code if someone wants to try it:仅供参考:如果有人想尝试,这是完整的代码:


using namespace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms

Add-Type -ReferencedAssemblies "System.Windows.Forms" -Language CSharp -TypeDefinition @'
using System;
public class VectorData {
    double _degrees = 0.0d;
    double _distance = 0.0d;
    public double Degrees {
        get {
            return this._degrees;
        }
        set {
            this._degrees = value;
        }
    }
    public double Distance {
        get {
            return this._distance;
        }
        set {
            this._distance = value;
        }
    }
    public string Display {
        get {
            return "" + this._degrees + "\u00B0 \u2192 " + this._distance + "\u0027";
        }
    }
    public VectorData(double degrees, double distance){
        this._degrees = degrees;
        this._distance = distance;
    }
}
'@
#$Vectors = [System.Collections.Generic.List[VectorData]]::new()
$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()
#$Vectors = [System.Collections.ObjectModel.ObservableCollection[VectorData]]::new()

#region Build form and controls
    function NextCtrlY { param ( [Control]$Control ) return $Control.Location.Y + $Control.Size.Height }

    $ClientWidth = 200
    $lbxVectors = [ListBox]@{
        Location = "12, 12"
        Name = "lbxVectors"
        Size = "$($ClientWidth - 24), 120"
        TabIndex = 0
    }

    $TextBoxWidth = ($ClientWidth - (12 + 6 + 12))/2
    $LeftTxBxX = 12 + $TextBoxWidth + 6
    $lblDegrees = [Label]@{
        AutoSize = $true
        Location = "12, $(NextCtrlY $lbxVectors)"
        Name = "lblDegrees"
        TabIndex = 1
        Text = "Degrees:"
    }

    $lblDistance = [Label]@{
        AutoSize = $true
        Location = "$LeftTxBxX, $(NextCtrlY $lbxVectors)"
        Name = "lblDistance"
        TabIndex = 2
        Text = "Distance:"
    }

    $txbDegrees = [TextBox]@{
        Location = "12, $(NextCtrlY $lblDegrees)"
        Name = "txbDegrees"
        Size = "$TextBoxWidth, 20"
        TabIndex = 3
        Text = ""
    }

    $txbDistance = [TextBox]@{
        Location = "$LeftTxBxX, $($txbDegrees.Location.Y)"
        Name = "txbDistance"
        Size = "$TextBoxWidth, 12"
        TabIndex = 4
        Text = ""
    }

    $ListBoxTestForm = [Form]@{
        ClientSize = "$ClientWidth, $($(NextCtrlY $txbDegrees) + 12)"
        FormBorderStyle = 'FixedDialog'
        MaximizeBox = $false
        MinimizeBox = $true
        Name = 'ListBoxTestForm'
        StartPosition = 'CenterScreen'
        Text = "ListBox Test"
    }

    $ListBoxTestForm.Controls.Add($lbxVectors)
    $ListBoxTestForm.Controls.Add($lblDegrees)
    $ListBoxTestForm.Controls.Add($lblDistance)
    $ListBoxTestForm.Controls.Add($txbDegrees)
    $ListBoxTestForm.Controls.Add($txbDistance)
#endregion


function SetVectorsDataSource {
    $lbxVectors.DataSource = $null
    $lbxVectors.DataSource = $Vectors
    $lbxVectors.DisplayMember = 'Display'
}
function BindTextBoxes {
    $VD = $Vectors[$lbxVectors.SelectedIndex]
    $null = $txbDegrees.DataBindings.Clear()
    $null = $txbDegrees.DataBindings.Add('Text', $VD, "Degrees")
    $null = $txbDistance.DataBindings.Clear()
    $null = $txbDistance.DataBindings.Add('Text', $VD, "Distance")
}

$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))
SetVectorsDataSource
BindTextBoxes
$lbxVectors.Add_SelectedIndexChanged({
    BindTextBoxes
})

$txbDegrees.Add_TextChanged({
#   SetVectorsDataSource
})
$txbDistance.Add_TextChanged({
#   SetVectorsDataSource
})

$null = $ListBoxTestForm.ShowDialog()

As I was about to post this question, I looked at the list of "Similar questions" and found this C# question/answer .当我正要发布这个问题时,我查看了“类似问题”列表并找到了这个 C# 问题/答案

Replaced the core code with the following and it works::用以下代码替换了核心代码并且它有效::

$VectorBindingSource = [BindingSource]::new()
$VectorBindingSource.DataSource = $Vectors

$lbxVectors.DataSource = $VectorBindingSource
$lbxVectors.DisplayMember = "Display"
$lbxVectors.ValueMember = "Display"

$null = $txbDegrees.DataBindings.Add("Text", $VectorBindingSource, "Degrees", $true, [DataSourceUpdateMode]::OnPropertyChanged)
$null = $txbDistance.DataBindings.Add("Text", $VectorBindingSource, "Distance", $true, [DataSourceUpdateMode]::OnPropertyChanged)
$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))

NOTE: Requires BindingList, doesn't work with generic list or ObservableCollection:注意:需要 BindingList,不适用于通用列表或 ObservableCollection:

$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM