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