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# 绑定到对象的ListView中的文本框,双向绑定dosen';行不通_C#_Wpf_Xaml_Datatemplate - Fatal编程技术网

C# 绑定到对象的ListView中的文本框,双向绑定dosen';行不通

C# 绑定到对象的ListView中的文本框,双向绑定dosen';行不通,c#,wpf,xaml,datatemplate,C#,Wpf,Xaml,Datatemplate,编辑: 好了,在没有运气的情况下,我终于玩了很多次之后,我创建了一个非常小的Wpf应用程序。您可以直接复制此代码。请注意,当您更改文本框中的值并按下测试按钮时,这些值永远不会更新。我不明白为什么双向装订不起作用。请帮忙 以下是xaml: <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height

编辑:

好了,在没有运气的情况下,我终于玩了很多次之后,我创建了一个非常小的Wpf应用程序。您可以直接复制此代码。请注意,当您更改文本框中的值并按下测试按钮时,这些值永远不会更新。我不明白为什么双向装订不起作用。请帮忙

以下是xaml:

<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
    (默认值为
    LostFocus
    )在UI->VM方向是必需的,而不是反向。因此,它在这里是无用的。您可以将其应用到模板中的
    文本框中

编辑

因为双向
绑定
需要显式
路径
,并且目标必须是包含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>