我有一个项目列表,我希望在一个项目列表中显示。ListView/GridView
. 每个项目都是一个包含格式和字节数组的类对象,格式决定了字节的显示方式(十六进制或十进制)。 格式决定了字节的显示方式(十六进制或十进制)。 我使用了一个转换器来回切换到 TextBox.Text
和字节数组。
转换器需要格式和字符串数组。 我试着用 IValueConverter
并将格式作为一个 ConverterParameter
但这并不奏效,因为它不是一个 DependencyProperty
. 我试着用 IMultiValueConverter
但这并不奏效,因为我没有得到的格式在 ConvertBack
. 我想,如果我可以绑定到整个对象(MyDataItem),那么转换器就可以正常工作。 然而,我不知道如何绑定到这个对象。 我尝试了一系列的变化,使用 RelativeSource
和其他属性,但是想不通。 谁能帮我解决绑定问题?
如果有更好的方法来完成我的任务,欢迎提出来。
public enum FormatEnum
{
Decimal,
Hex
}
public class MyDataItem
{
public byte[] Data { get; set; }
public FormatEnum Format { get; set; }
}
public class ViewModel
{
ObservableCollection<MyDataItem> DataItems = new ObservableCollection<MyDataItem>();
}
XAML(含非工作绑定)
<ListView ItemsSource="{Binding DataItems}">
<ListView.View>
<GridView>
<GridViewColumn Header="Format">
<GridViewColumn.CellTemplate>
<DataTemplate>
<!--ComboBox for the format-->
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Data">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path,
Converter={StaticResource ResourceKey=DataBytesConverter},
ConverterParameter={Binding Format}}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
欢迎来到SO!
欢迎来到SO.S.O.!只是为将来提个醒......如果你提供了一个问题,你会有更大的机会得到回答。MCVE. 你让人们为重现你的确切问题所做的工作越多,他们就越不愿意这样做。
有几种不同的方法来完成你想做的事情,但主要问题是你绑定的数据不支持 INPC. 我让你去读一读,但问题本质上是左手(你的文本显示域)不知道右手(ComboBox)在做什么。当 ComboBox 改变格式时,它必须向任何依赖于它的东西发出信号,说明值已经改变。这就是INPC的作用。如果你愿意的话,你可以自己实现它,网上有很多教程展示如何实现它,但只使用现有的库,如 MVVM灯这就是我在这里要使用的。
在我详细介绍之前,我应该指出,你使用IMultiValueConverter的想法其实是可行的,前提是你把Data和Format作为单独的参数传入,这样每当它们中的任何一个改变值时,它就会更新。其实很多人都会提出这样的解决方案,但这并不是你想实现的最佳方式。转换器和行为实际上只是视图的扩展,当它们暴露了视图的部分时,这是很好的,否则你无法进入。但在你的案例中,问题在于你提供给视图的数据并不是你的视图可以轻易消耗的格式,而在一个 "正确的 "WPF应用程序中,它应该是这样的。事先修复你的数据通常会更快,出错时调试起来也更容易,而且它为单元测试等事情提供了可能性。我们已经知道,为了支持INPC,你的MyDataItem类必须被修改或替换,所以这是一个很好的地方来做你的值到文本逻辑。
因此,首先,为你的模型对象创建一个视图模型,该模型暴露了你想传递给你的视图laye的属性(即 "Format"),并为你想显示的文本字符串添加一个新的属性(即 "DataText")。我们还将创建一个更新函数来填充该字符串,INPC支持和一小部分更新逻辑。
public class MyDataItemViewModel : ViewModelBase
{
private MyDataItem DataItem;
public MyDataItemViewModel(MyDataItem dataItem)
{
this.DataItem = dataItem;
UpdateDataText();
}
public FormatEnum Format
{
get { return this.DataItem.Format; }
set
{
if (this.DataItem.Format != value)
{
this.DataItem.Format = value;
RaisePropertyChanged(() => this.Format);
UpdateDataText();
}
}
}
private string _DataText;
public string DataText
{
get { return this._DataText; }
set
{
if (this._DataText != value)
{
this._DataText = value;
RaisePropertyChanged(() => this.DataText);
}
}
}
private void UpdateDataText()
{
switch (this.Format)
{
case FormatEnum.Decimal:
this.DataText = String.Join(", ", this.DataItem.Data.Select(val => String.Format("{0:D}", val)));
break;
case FormatEnum.Hex:
this.DataText = String.Join(", ", this.DataItem.Data.Select(val => String.Format("0x{0:X2}", val)));
break;
default:
this.DataText = String.Empty;
break;
}
}
}
你的 "DataItems "集合需要是公共的,并且可以通过getter来访问(你在原始代码中没有这样做),而且它需要是这些视图模型的集合。
public ObservableCollection<MyDataItemViewModel> DataItems { get; } = new ObservableCollection<MyDataItemViewModel>();
现在对于每一个MyDataItem的实例 你都要把它包裹在MyDataItemViewModel的实例中。
this.DataItems.Add(new MyDataItemViewModel(new MyDataItem { Format = FormatEnum.Decimal, Data = new byte[] { 1, 2, 3 } }));
this.DataItems.Add(new MyDataItemViewModel(new MyDataItem { Format = FormatEnum.Decimal, Data = new byte[] { 4, 5, 6 } }));
现在你的数据的格式就好很多了。ObjectDataProvider提供了一个很好的、方便的方法来把一个特定类型的Enum的所有值放在一个单一的列表中,一个ComboBox可以绑定到这个列表,所以让我们为你的FormatEnum创建一个这样的列表。
xmlns:system="clr-namespace:System;assembly=mscorlib"
<Window.Resources>
<ObjectDataProvider x:Key="FormatEnumValues" MethodName="GetValues" ObjectType="{x:Type system:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:FormatEnum"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
现在你的ListView可以直接绑定到这些数据上 而不需要任何转换器或行为或其他类似的乱七八糟的东西。
<ListView ItemsSource="{Binding DataItems}">
<ListView.View>
<GridView>
<GridViewColumn Header="Format">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource FormatEnumValues}}" SelectedItem="{Binding Path=Format}" Width="100" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Data">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataText}" TextTrimming="CharacterEllipsis" MinWidth="100" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
结果: