Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过mvvm将wpf数据网格绑定到包含组合框和测试框组合的列_C#_Wpf_Mvvm_Datagridviewcolumn - Fatal编程技术网

C# 如何通过mvvm将wpf数据网格绑定到包含组合框和测试框组合的列

C# 如何通过mvvm将wpf数据网格绑定到包含组合框和测试框组合的列,c#,wpf,mvvm,datagridviewcolumn,C#,Wpf,Mvvm,Datagridviewcolumn,在我的datagrid中,我有一个textbox列和另一个列,其中应该包含组合框和文本框的组合,应该动态设置。例如,我让用户设置机器的状态。所以,State和Value是每个列的标题,其中Value可以包含一个组合框或文本框,具体取决于状态的类型。其类型可以是布尔或枚举。如果是枚举,则显示组合框else文本框 我试图通过视图模型来实现这一点,但我不确定如何在xaml中设置DataGridview。或者在这种情况下有可能 <DataGrid Name="dataGridView" Items

在我的datagrid中,我有一个textbox列和另一个列,其中应该包含组合框和文本框的组合,应该动态设置。例如,我让用户设置机器的状态。所以,State和Value是每个列的标题,其中Value可以包含一个组合框或文本框,具体取决于状态的类型。其类型可以是布尔或枚举。如果是枚举,则显示组合框else文本框

我试图通过视图模型来实现这一点,但我不确定如何在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>();
private observeCollection state参数列表=
新的可观察集合();
公共可见收集状态参数列表
{
获取{return StateParametersList;}
设置
{
StateParametersList=值;
NotifyPropertyChanged(nameof(StateParametersList));
}
}
[可序列化]
公共类状态参数
{
公共字符串状态{get;set;}
公共对象值{get;set;}
}
List ValueCell=新列表();
其中ValueCell是组合框中在运行时填充的项目列表


所以,我可以通过xaml.cs文件完成这项工作,并根据其枚举与否创建组合框,但我希望通过视图模型实现这一点。而且,每个组合框将具有不同的值,这些值在运行时动态填充。我在这里苦苦挣扎,因此,如果有人能为我指出正确的方向,我将不胜感激。

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; }
    }
}
至此,我们已经完成了C#代码端的部分,接下来我们将进入DataGrid


3。UI/XAML

由于不同的状态参数类别需要不同的交互元素(复选框、文本框、组合框),我们将尝试利用DataTemplates来定义每个状态参数类别在DataGrid单元格中的表示方式

现在,很明显我们为什么要努力定义这些类别,并为每个类别声明不同的状态参数类型。因为数据模板可以与特定类型关联。现在我们将为每个
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>
就这样。通过对底层数据模型(状态参数类)的小小扩展,XAML问题就消失了(我希望如此)


4。演示数据集

用于演示实际代码的快速测试数据集(使用随机选取的枚举类型作为示例):

StateParametersList=新的ObservableCollection
{
新boolstate参数
{
State=“Bool1”,
值=假
},
新ChoiceState参数
{
State=“Enum FileShare”,
值=System.IO.FileShare.ReadWrite,
选项=Enum.GetValues(typeof(System.IO.FileShare))
},
新的TextStateParameter
{
State=“Text1”,
Value=“你好”
},
新boolstate参数
{
State=“Bool2”,
值=真
},
新ChoiceState参数
{
State=“Enum ConsoleKey”,
值=System.ConsoleKey.Backspace,
选项=Enum.GetValues(typeof(System.ConsoleKey))
},
新的TextStateParameter
{
State=“Text2”,
Value=“世界”
}
};
它将如下所示:


为什么需要表示布尔参数的文本框?复选框不是表示布尔参数的更好选择吗?是的,复选框也很理想。但是,如何在动态填充的datagrid中组合使用复选框和组合框呢?我已经知道如何解决您的问题,但请允许我再问一个问题,以便更好地处理可能的解决方案:正如您已经注意到的,您的简单StateParameters数据模式
    public class TextStateParameter : StateParameter<string>
    { }
    public class ChoiceStateParameter : StateParameter<object>
    {
        public Array Choices { get; set; }
    }
public ObservableCollection<IStateParameter> StateParametersList { get ..... set ..... }
<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>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding State}"/>

        <DataGridTemplateColumn Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ContentPresenter Content="{Binding}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>

</DataGrid>
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"
    }
};