亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何通過 mvvm 將 wpf 數據網格綁定到包含組合框和測試框組合的列

如何通過 mvvm 將 wpf 數據網格綁定到包含組合框和測試框組合的列

C#
一只萌萌小番薯 2023-04-29 16:54:52
在我的數據網格中,我有一個文本框列和另一列應該包含應該動態設置的組合框和文本框的組合。例如,我讓用戶設置機器的狀態。因此,State 和 Value 是每列的標題,其中 Value 可以根據 State 的類型包含組合框或文本框。它的類型可以是布爾值或枚舉。如果是枚舉,則顯示組合框,否則顯示文本框。我正在嘗試通過視圖模型執行此操作,但我不確定如何在 xaml 中設置 DataGridview?;蛘咴谶@種情況下是否有可能......?<DataGrid Name="dataGridView" ItemsSource="{Binding Path=StateParametersList}" CanUserAddRows="False"                       IsReadOnly="True" >                <DataGrid.Columns>                    <DataGridTextColumn Binding="{Binding State}"/>                    <DataGridTemplateColumn>                        <DataGridTemplateColumn.CellEditingTemplate>                            <DataTemplate>                                <ComboBox ItemsSource="{Binding ValueCell}" SelectedItem="{Binding Value}"/>                            </DataTemplate>                        </DataGridTemplateColumn.CellEditingTemplate>                    </DataGridTemplateColumn>                </DataGrid.Columns>            </DataGrid>視圖模型:private ObservableCollection<StateParameters> StateParametersList =        new ObservableCollection<StateParameters>();    public ObservableCollection<StateParameters> StateParametersList    {        get { return StateParametersList; }        set        {            StateParametersList = value;            NotifyPropertyChanged(nameof(StateParametersList));        }    }[Serializable]public class StateParameters{    public string State { get; set; }    public object Value { get; set; }}List<string> ValueCell = new List<string>();其中 ValueCell 將是將在運行時填充的組合框中的項目列表。所以,我本可以通過 xaml.cs 文件完成此操作,并根據其是否枚舉創建組合框,但我想通過視圖模型實現此目的。而且,每個組合框都有不同的值,這些值在運行時動態填充。我在這里掙扎,因此,如果有人能指出我正確的方向,將不勝感激。
查看完整描述

1 回答

?
尚方寶劍之說

TA貢獻1788條經驗 獲得超4個贊

1.組織狀態參數數據模型

在查看所需的用戶交互時,存在不同類別的狀態參數,這些狀態參數是關于它們如何呈現給用戶/由用戶編輯的。在問題的范圍內,我們可以確定以下類別:

  • 可切換參數 ( bool)

  • 一個選擇參數,其中參數的值是給定集合中的一個(實際上就像枚舉或任何其他數據類型)

  • 為了更好地衡量,文本參數 ( string)


2.實現狀態參數數據模型

狀態參數具有狀態名稱/標識符和值。該值可以是不同的類型。這本質上是問題中StateParameters類的定義。

但是,正如我稍后的回答中將變得更加明顯的那樣,具有代表上面列出的不同類別狀態參數的不同類型/類將有利于在 UI 中連接表示和交互邏輯。

當然,無論其類別如何,每個狀態參數都應該由相同的基類型表示。顯而易見的選擇是使狀態參數基類型成為抽象類或接口。在這里,我選擇了一個界面:

public interface IStateParameter

{

    string State { get; }

    object Value { get; set; }

}

我現在沒有根據上面列出的類別直接創建具體的狀態參數類,而是創建了一個額外的抽象基類。這個類將是通用的,使得以類型安全的方式處理狀態參數更容易一些:


public abstract class StateParameter<T> : IStateParameter, INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;


    public string State { get; set; }


    public T Value

    {

        get { return _v; }

        set

        {

            if ((_v as IEquatable<T>)?.Equals(value) == true || ReferenceEquals(_v, value) || _v?.Equals(value) == true)

                return;


            _v = value;

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));

        }

    }


    private T _v;


    object IStateParameter.Value

    {

        get { return this.Value; }

        set { this.Value = (T) value; }

    }

}

(雖然該State屬性有一個設置器,但該屬性只能設置一次,因此不需要屬性更改通知。從技術上講,您可以隨時更改該屬性;我只是選擇在這里使用一個設置器來保存代碼我的回答相對簡短。)


請注意接口的實現INotifyPropertyChanged,這是必要的,因為 UI 將Value通過綁定操作屬性。還要注意接口屬性的顯式接口實現,它將“隱藏”它,除非您將狀態參數對象引用顯式轉換為。這是有意為之的,因為它提供了自己的類型屬性,該類型與StateParameter<T>的泛型類型參數相匹配。此外,不幸的是,setter 中的相等比較有點尷尬,因為泛型類型參數IStateParameterValueIStateParameterStateParameter<T>ValueValueT這里是完全不受約束的,可以是某種值類型或某種引用類型。因此,相等比較必須涵蓋所有可能發生的情況。


因此,完成這些準備工作后,是時候將我們的注意力放回到實際問題上了。我們現在將根據答案開頭概述的類別來實現具體的狀態參數類型:


    public class BoolStateParameter : StateParameter<bool>

    { }

    public class TextStateParameter : StateParameter<string>

    { }

    public class ChoiceStateParameter : StateParameter<object>

    {

        public Array Choices { get; set; }

    }

ChoiceStateParameter類聲明了一個附加屬性,該屬性用于保存數組,其中包含可供特定狀態參數選擇的可能值。(就像上面的StateParameter<T>.State一樣,這個屬性只能設置一次,我在這里給它一個 setter 的原因是為了讓我的答案中的代碼相對簡短。)


除了ChoiceStateParameter類之外,其他類中沒有任何聲明。你會問,如果我們可以直接使用StateParameter<bool>/StateParameter<string>為什么還需要BoolStateParameter/TextStateParameter ?這是個好問題。如果我們不必處理 XAML,我們可以輕松地直接使用StateParameter<bool>/StateParameter<string>(假設 _StateParameter<T> 不是抽象類)。但是,嘗試從 XAML 標記中引用泛型類型是一件介于非常痛苦和完全不可能之間的事情。因此,非通用具體狀態參數類BoolStateParameter、TextStateParameter和ChoiceStateParameter已被定義。


哦,在我們忘記之前,因為我們已經將公共狀態參數基類型聲明為名為 的接口IStateParameter,所以必須相應地調整視圖模型中屬性的類型參數StateParametersList(當然還有它的支持字段):


public ObservableCollection<IStateParameter> StateParametersList { get ..... set ..... }

完成后,我們就完成了 C# 代碼方面的部分,我們將繼續處理 DataGrid。



3. 用戶界面/XAML


由于不同的狀態參數類別需要不同的交互元素(CheckBoxes、TextBoxes、ComboBoxes),我們將嘗試利用 DataTemplates 來定義每個狀態參數類別應如何在 DataGrid 單元格內表示。


現在,我們努力定義這些類別并為每個類別聲明不同的狀態參數類型的原因也將變得顯而易見。因為 DataTemplates 可以與特定類型相關聯。我們現在將為每個BoolStateParameter,TextStateParameter和ChoiceStateParameter類型定義那些數據模板。


DataTemplates 將放置在 DataGrid 中,作為 DataGrid 資源字典的一部分:


<DataGrid Name="dataGridView" ItemsSource="{Binding Path=StateParametersList}" ... >


    <DataGrid.Resources>

        <DataTemplate DataType="{x:Type local:BoolStateParameter}">

            <CheckBox IsChecked="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />

        </DataTemplate>


        <DataTemplate DataType="{x:Type local:TextStateParameter}">

            <TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />

        </DataTemplate>


        <DataTemplate DataType="{x:Type local:ChoiceStateParameter}">

            <ComboBox ItemsSource="{Binding Choices}" SelectedItem="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />

        </DataTemplate>

    </DataGrid.Resources>

(注意:您可能需要調整local:我在此處使用的名稱空間,或將其與映射到聲明狀態參數類的 C# 名稱空間的 XML 名稱空間交換。)


下一步是讓DataGridTemplateColumn根據它在給定列單元格中處理的狀態參數的實際類型選擇適當的 DataTemplate。但是,DataGridTemplateColumn不能從資源字典本身中選擇 DataTemplate,DataGrid控件也不能代表DataGridTemplateColumn這樣做。所以現在怎么辦?


幸運的是,WPF 中有一些 UI 元素使用資源字典中的 DataTemplate 呈現一些值/對象,并根據值/對象的類型選擇 DataTemplate。一個這樣的 UI 元素是ContentPresenter,我們將在DataGridTemplateColumn中使用它:


    <DataGrid.Columns>

        <DataGridTextColumn Binding="{Binding State}"/>


        <DataGridTemplateColumn Width="*">

            <DataGridTemplateColumn.CellTemplate>

                <DataTemplate>

                    <ContentPresenter Content="{Binding}" />

                </DataTemplate>

            </DataGridTemplateColumn.CellTemplate>

        </DataGridTemplateColumn>

    </DataGrid.Columns>


</DataGrid>

就是這樣。隨著底層數據模型(狀態參數類)的小幅擴展,XAML 問題就消失了(我希望如此)。



4. 演示數據集


用于演示實際代碼的快速測試數據集(使用隨機選擇的枚舉類型作為示例):


StateParametersList = new ObservableCollection<IStateParameter>

{

    new BoolStateParameter

    {

        State = "Bool1",

        Value = false

    },

    new ChoiceStateParameter

    {

        State = "Enum FileShare",

        Value = System.IO.FileShare.ReadWrite,

        Choices = Enum.GetValues(typeof(System.IO.FileShare))

    },

    new TextStateParameter

    {

        State = "Text1",

        Value = "Hello"

    },

    new BoolStateParameter

    {

        State = "Bool2",

        Value = true

    },

    new ChoiceStateParameter

    {

        State = "Enum ConsoleKey",

        Value = System.ConsoleKey.Backspace,

        Choices = Enum.GetValues(typeof(System.ConsoleKey))

    },

    new TextStateParameter

    {

        State = "Text2",

        Value = "World"

    }

};

它看起來像這樣:

http://img1.sycdn.imooc.com//644cdb880001043e04360146.jpg

查看完整回答
反對 回復 2023-04-29
  • 1 回答
  • 0 關注
  • 220 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號