C# 绑定到对象的ListView中的文本框,双向绑定dosen';行不通
编辑: 好了,在没有运气的情况下,我终于玩了很多次之后,我创建了一个非常小的Wpf应用程序。您可以直接复制此代码。请注意,当您更改文本框中的值并按下测试按钮时,这些值永远不会更新。我不明白为什么双向装订不起作用。请帮忙 以下是xaml:C# 绑定到对象的ListView中的文本框,双向绑定dosen';行不通,c#,wpf,xaml,datatemplate,C#,Wpf,Xaml,Datatemplate,编辑: 好了,在没有运气的情况下,我终于玩了很多次之后,我创建了一个非常小的Wpf应用程序。您可以直接复制此代码。请注意,当您更改文本框中的值并按下测试按钮时,这些值永远不会更新。我不明白为什么双向装订不起作用。请帮忙 以下是xaml: <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Grid.Row="0"
ItemsSource="{Binding Path=Demo.CurrentParameterValue,Mode=TwoWay}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=.,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100"></TextBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Grid.Row="1" Click="Button_Click">TEST</Button>
</Grid>
试验
以下是xaml.cs:
namespace WpfApp9
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private VmServiceMethodsViewDataGridModel _demo;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public VmServiceMethodsViewDataGridModel Demo
{
get => _demo;
set
{
_demo = value;
OnPropertyChanged("Demo");
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
Demo = new VmServiceMethodsViewDataGridModel();
Demo.CurrentParameterValue.Add(1);
Demo.CurrentParameterValue.Add(2);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var collection = Demo.CurrentParameterValue;
MessageBox.Show(string.Format("Values are {0}, {1}", collection[0], collection[1]));
}
}
public class VmServiceMethodsViewDataGridModel : INotifyPropertyChanged
{
private List<object> _currentParameterValue;
public List<object> CurrentParameterValue
{
get => _currentParameterValue;
set
{
_currentParameterValue = value;
OnPropertyChanged("CurrentParameterValue");
}
}
public VmServiceMethodsViewDataGridModel()
{
CurrentParameterValue = new List<object>();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
名称空间WpfApp9
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口,INotifyPropertyChanged
{
私有VMServiceMethodViewDataGridModel_演示;
公共事件属性更改事件处理程序属性更改;
受保护的void OnPropertyChanged(字符串名称=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
公共VMServiceMethodViewDataGridModel演示
{
获取=>\u演示;
设置
{
_演示=价值;
OnPropertyChanged(“演示”);
}
}
公共主窗口()
{
初始化组件();
DataContext=this;
Demo=新的VMServiceMethodViewDataGridModel();
演示.CurrentParameterValue.Add(1);
演示.CurrentParameterValue.Add(2);
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
var collection=Demo.CurrentParameterValue;
Show(string.Format(“值为{0}、{1}”、集合[0]、集合[1]);
}
}
公共类VMServiceMethodViewDataGridModel:INotifyPropertyChanged
{
私有列表_currentParameterValue;
公共列表CurrentParameterValue
{
get=>\u currentParameterValue;
设置
{
_currentParameterValue=值;
OnPropertyChanged(“CurrentParameterValue”);
}
}
公共VMServiceMethodViewDataGridModel()
{
CurrentParameterValue=新列表();
}
公共事件属性更改事件处理程序属性更改;
受保护的void OnPropertyChanged(字符串名称=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
}
但是,当我更改文本框中的值时,它不会更新回CurrentParameterValue属性的源
ListView
中的Binding
不知道如何更新类型object
的属性,因为它是ItemsSource
并且只能更新ICollection
,例如您不能与对象
交互,比如C#中的List
。例如:
object MyList=new object();
MyList.Add(“某物”);//编译错误
在我的viewmodel中,对象可以是长列表、双列表等,它来自外部API
那么你需要这个解决方案
公共类VMServiceMethodViewDataGridModel:BindableBaseThreadSafe
{
私有列表_currentParameterValue;//或ObservableCollection
公共列表CurrentParameterValue
{
get=>\u currentParameterValue;
set=>set(ref\u currentParameterValue,value);
}
}
另外 我不知道你想用这种语法实现或解决什么问题
一切都必须与此配合
是默认模式,您可以不在此处明确包含它Mode=TwoWay
(默认值为UpdateSourceTrigger=PropertyChanged
)在UI->VM方向是必需的,而不是反向。因此,它在这里是无用的。您可以将其应用到模板中的LostFocus
文本框中
编辑 因为双向
绑定
需要显式路径
,并且目标必须是包含Setter的属性
您的演示应用程序的解决方案
public分部类主窗口:窗口,INotifyPropertyChanged
{
私有VMServiceMethodViewDataGridModel_演示;
公共事件属性更改事件处理程序属性更改;
受保护的void OnPropertyChanged(字符串名称=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
公共VMServiceMethodViewDataGridModel演示
{
获取=>\u演示;
设置
{
_演示=价值;
OnPropertyChanged(“演示”);
}
}
公共主窗口()
{
初始化组件();
DataContext=this;
Demo=新的VMServiceMethodViewDataGridModel();
Demo.CurrentParameterValue.Add(新的MyItem{Value=1});
Demo.CurrentParameterValue.Add(新的MyItem{Value=2});
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
var collection=Demo.CurrentParameterValue;
Show(string.Format(“值为{0},{1}”,集合[0].Value,集合[1].Value));
}
}
//给你
公共类MyItem
{
公共对象值{get;set;}
}
公共类VMServiceMethodViewDataGridModel:INotifyPropertyChanged
{
私有列表_currentParameterValue;
公共列表CurrentParameterValue
{
get=>\u currentParameterValue;
设置
{
_currentParameterValue=值;
OnPropertyChanged(“CurrentParameterValue”);
}
}
公共VMServiceMethodViewDataGridModel()
{
CurrentParameterValue=新列表();
}
公共事件属性更改事件处理程序属性更改;
受保护的不动产
<ListView ItemsSource="{Binding CurrentParameterValue.ListParameterValues}">
// An async void method must return Task
private async Task GetParameterList(string obj)
protected virtual void Set<TValue>(out TValue valueTarget, TValue value, [CallerMemberName] string propertyName = null)
{
if (value != valueTarget)
{
valueTarget = value;
OnPropertyChanged(propertyName);
}
}
// The type that wraps the actual parameter value.
// Consider to use dedicated types e.g., LongParameter instead, to allow a strongly typed Value property instead of a basic property of type object.
// This prevents implicit boxing/unboxing in order to convert from object/reference type to primitive/value type and vice versa. This will improve performance.
// (Only needed because we are dealing with primitive/value types like long, double, etc)
// You would then have to define a DataTemplate for each type. Don't forget to set x:DataType on each DataTemplate.
public class Parameter : BindableBase
{
protected Parameter(object value)
{
this.Value = value;
}
private object value;
public object Value
{
get => this.value;
set => Set(out this.value, value);
}
}
public class VmServiceModel : BindableBase
{
public VmServiceModel()
{
this.Parameters = new List<Parameter>();
}
private List<Parameter> _parameters;
public List<Parameter> Parameters
{
get => this._parameters;
set => Set(out this._parameters, value);
}
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
this.AtlasMethodParameterList = new ObservableCollection<VmServiceModel>();
}
private ObservableCollection<VmServiceModel> _atlasMethodParameterList;
public ObservableCollection<VmServiceModel> AtlasMethodParameterList
{
get => _atlasMethodParameterList;
set => Set(out _atlasMethodParameterList, value);
}
private async Task GetParameterList(string obj)
{
foreach (var item in this.ParametersCollection)
{
var vmServiceModel = new VmServiceModel();
vmServiceModel.Parameters
.AddRange(item.Value.Cast<long>().Select(innerItem => new Parameter(innerItem)));
this.AtlasMethodParameterList.Add(vmServiceModel);
}
}
}
public sealed partial class MainPage : Page
{
public ViewModel ViewModel { get; set; }
public MainPage()
{
this.InitializeComponent();
this.ViewModel = new ViewModel();
}
}
<Page>
<Page.Resources>
<DataTemplate x:Key="ListIntTemplate" x:DataType="local:VmServiceModel">
<ListView ItemsSource="{x:Bind Parameters}"
HorizontalAlignment="Center"
SelectionMode="None" Background="Transparent">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Parameter">
<TextBox Text="{Binding Value Mode=TwoWay}" Height="36" Width="65"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</Page.Resources>
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.AtlasMethodParameterList}"
ItemTemplate="{StaticResource ListIntTemplate}">
</ListView>
</Grid>
</Page>