C# 如何在WPF中进行多项目数据绑定
我有一个特殊的场景。我的应用程序看起来像这样 在左侧有一些用户列表,它是一个列表框,在右侧有几个字段,这些字段是绑定到左侧的数据。它的工作原理是,如果您在右侧选择“用户1”,将显示用户1相关信息,您可以修改该信息,并且其数据绑定为C# 如何在WPF中进行多项目数据绑定,c#,wpf,xaml,mvvm,data-binding,C#,Wpf,Xaml,Mvvm,Data Binding,我有一个特殊的场景。我的应用程序看起来像这样 在左侧有一些用户列表,它是一个列表框,在右侧有几个字段,这些字段是绑定到左侧的数据。它的工作原理是,如果您在右侧选择“用户1”,将显示用户1相关信息,您可以修改该信息,并且其数据绑定为“UpdateSourceTrigger=PropertyChanged”,因此它也会立即反映在左侧。其他用户也是如此 现在的问题是,如果我选择多个用户并编辑一个字段,比如说字段3,它是可编辑的文本框。现在,如果我选择用户1并编辑此文本框,它将反映在用户1的“备注:…”
“UpdateSourceTrigger=PropertyChanged”
,因此它也会立即反映在左侧。其他用户也是如此
现在的问题是,如果我选择多个用户并编辑一个字段,比如说字段3,它是可编辑的文本框。现在,如果我选择用户1并编辑此文本框,它将反映在用户1的“备注:…”中,如果我选择用户2并编辑字段3,它将更新用户2的“备注:…”,但如果是多选,我如何实现它?假设我想同时选择用户1和用户2并编辑注释字段,它应该更新用户1和用户2的注释字段,并且数据绑定也应该工作,我的意思是它应该立即将我输入的文本输入文本框。有什么办法可以做到这一点吗
当前在我的viewModel中
模型
看法
在XAML中,用户列表框项模板的定义如下
<TextBlock Text="{Binding Note, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
在XAML中,右侧文本框(字段3)以相同的方式进行数据绑定
<TextBox Text="{Binding Note, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
如何实现多用户数据绑定
请帮助我,给我一些想法
编辑:
转换器:
公共类MultiBindingConverter:IValueConverter
{
可观察到的集合;
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
var coll=(可观测采集)值;
mycollection=coll;
如果(coll.Count==1)
{
if(parameter.ToString()=“FNote”)
返回coll[0];
}
否则,如果(列数>1)
{
//字符串名称=coll[0]。FirstName;
if(parameter.ToString()=“FNote”)
{
字符串名称=coll[0]。注意;
foreach(coll中的c变量)
{
如果(c.注释!=名称)
返回null;
否则继续;
}
返回名称;
}
}
返回null;
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
if(parameter.ToString()=“FNote”)
{
foreach(mycollection中的var c)
{
c、 注意=value.ToString();
}
回采;
}
返回null;
}
}
对于我来说,只有一个文本框可编辑的NoteTextBox需要与多个用户建立数据索引
在我的ViewModel中
我写过
视图模型
private命令选择changedCommand;
公共命令选择更改命令
{
收到
{
如果(selectionChangedCommand==null)
{
selectionChangedCommand=新命令(SelectionChanged,true);
}
返回selectionChangedCommand;
}
设置{selectionChangedCommand=value;}
}
公共无效选择已更改(对象值)
{
selectedItem=newobservetecollection((值为IEnumerable).OfType());
}
私有可观察集合selectedItem;
公共可见集合SelectedItem
{
获取{return selectedItem;}
设置
{
选择editem=值;
财产变更(“SelectedItem”);
}
}
在
Info
类中,有一个属性Note
,需要绑定到视图的两个位置。您不能仅通过数据绑定来实现这一点,因为在某些情况下,您需要做出逻辑决策
例如,如果user1和user2有不同的notetext,那么当两者都被选中时,就不能同时显示两者。相反,我想您需要某种方法来指定您想要“保留原始文本”,或者允许用户过度键入以将两个文本设置为相同
无论您想要什么,您都需要在viewmodel中有单独的绑定源,以便您可以独立地更新它们并做出逻辑决策。您不能仅通过数据绑定来实现这一点,因为在某些情况下您需要做出逻辑决策 例如,如果user1和user2有不同的notetext,那么当两者都被选中时,就不能同时显示两者。相反,我想您需要某种方法来指定您想要“保留原始文本”,或者允许用户过度键入以将两个文本设置为相同
无论您想要什么,都需要在viewmodel中有单独的绑定源,以便您可以独立更新它们并做出逻辑决策。我尝试了一些我知道的东西,得到了与您要求相同的输出。如果我错了,请纠正我
XAML
模型
视图模型
公共类视图模型:INotifyPropertyChanged
{
私有MyCommand和selectionChangedCommand;
公共MyCommand选择更改命令
{
收到
{
如果(selectionChangedCommand==null)
{
selectionChangedCommand=新的MyCommand(SelectionChanged);
}
返回selectionChangedCommand;
}
设置{selectionChangedCommand=value;}
}
公共无效选择已更改(对象值)
{
SelectedItem=newobservetecollection((值为IEnumerable).OfType());
}
私人观察者
<TextBox Text="{Binding Note, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
public class MultiBindingConverter : IValueConverter
{
ObservableCollection<Info> mycollection;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var coll = (ObservableCollection<Info>)value;
mycollection = coll;
if (coll.Count == 1)
{
if (parameter.ToString() == "FNote")
return coll[0];
}
else if (coll.Count > 1)
{
// string name = coll[0].FirstName;
if (parameter.ToString() == "FNote")
{
string name = coll[0].Note;
foreach (var c in coll)
{
if (c.Note != name)
return null;
else continue;
}
return name;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter.ToString() == "FNote")
{
foreach (var c in mycollection)
{
c.Note = value.ToString();
}
return mycollection;
}
return null;
}
}
private Command selectionChangedCommand;
public Command SelectionChangedCommand
{
get
{
if (selectionChangedCommand == null)
{
selectionChangedCommand = new Command(SelectionChanged, true);
}
return selectionChangedCommand;
}
set { selectionChangedCommand = value; }
}
public void SelectionChanged(object value)
{
selectedItem = new ObservableCollection<Info>((value as IEnumerable).OfType<Info>());
}
private ObservableCollection<Info> selectedItem;
public ObservableCollection<Info> SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
PropertyChanged("SelectedItem");
}
}
<Window x:Class="MVVM_sample_ListBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVM_sample_ListBox"
Title="MainWindow" Height="350" Width="525"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<Window.Resources>
<local:Converter x:Key="Converter"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="235*" />
<ColumnDefinition Width="268*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="lb" SelectionMode="Multiple" Grid.Row="0" ItemsSource="{Binding MyCollection}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp" >
<i:InvokeCommandAction CommandParameter="{Binding SelectedItems, ElementName=lb}" Command="{Binding SelectionChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding SecondName}"/>
<TextBlock Text="{Binding Company}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Column="1" >
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Text="{Binding SelectedItem,ConverterParameter=FName, Converter={StaticResource Converter}}" Name="textBox1" VerticalAlignment="Top" Width="120" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Text="{Binding SelectedItem,ConverterParameter=SName, Converter={StaticResource Converter}}" Name="textBox2" VerticalAlignment="Top" Width="120" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Text="{Binding SelectedItem,ConverterParameter=Comp, Converter={StaticResource Converter}}" Name="textBox3" VerticalAlignment="Top" Width="120" />
</StackPanel>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class Model : INotifyPropertyChanged
{
private string fname;
public string FirstName
{
get { return fname; }
set { fname = value;RaisePropertyChanged("FirstName"); }
}
private string sname;
public string SecondName
{
get { return sname; }
set { sname = value; RaisePropertyChanged("SecondName");}
}
private string company;
public string Company
{
get { return company; }
set { company = value;RaisePropertyChanged("Company"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
{
if(PropertyChanged!= null)
{
this.PropertyChanged(this,new PropertyChangedEventArgs(name));
}
}
}
public class ViewModel : INotifyPropertyChanged
{
private MyCommand selectionChangedCommand;
public MyCommand SelectionChangedCommand
{
get
{
if (selectionChangedCommand == null)
{
selectionChangedCommand = new MyCommand(SelectionChanged);
}
return selectionChangedCommand;
}
set { selectionChangedCommand = value; }
}
public void SelectionChanged(object value)
{
SelectedItem = new ObservableCollection<Model>((value as IEnumerable).OfType<Model>());
}
private ObservableCollection<Model> selectedItem;
public ObservableCollection<Model> SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; RaisePropertyChanged("SelectedItem"); }
}
private ObservableCollection<Model> mycoll;
public ObservableCollection<Model> MyCollection
{
get { return mycoll;}
set { mycoll = value;}
}
public ViewModel()
{
SelectedItem = new ObservableCollection<Model>();
SelectedItem.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SelectedItem_CollectionChanged);
MyCollection = new ObservableCollection<Model>();
MyCollection.Add(new Model { FirstName = "aaaaa", SecondName = "bbbbb", Company = "ccccccc" });
MyCollection.Add(new Model { FirstName = "ddddd", SecondName = "bbbbb", Company = "eeeeeee" });
MyCollection.Add(new Model { FirstName = "fffff", SecondName = "gggggg", Company = "ccccccc" });
}
void SelectedItem_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
//this.SelectedItem =new ObservableCollection<Model>((sender as ObservableCollection<Model>).Distinct());
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
{
if(PropertyChanged!= null)
{
this.PropertyChanged(this,new PropertyChangedEventArgs(name));
}
}
}
public class MyCommand : ICommand
{
private Action<object> _execute;
private Predicate<object> _canexecute;
public MyCommand(Action<object> execute, Predicate<object> canexecute)
{
_execute = execute;
_canexecute = canexecute;
}
public MyCommand(Action<object> execute)
: this(execute, null)
{
_execute = execute;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (parameter == null)
return true;
if (_canexecute != null)
{
return _canexecute(parameter);
}
else
{
return true;
}
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}
public class Converter : IValueConverter
{
ObservableCollection<Model> mycollection;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var coll = (ObservableCollection<Model>)value;
mycollection = coll;
if (coll.Count == 1)
{
if (parameter.ToString() == "FName")
return coll[0].FirstName;
else if (parameter.ToString() == "SName")
return coll[0].SecondName;
else if (parameter.ToString() == "Comp")
return coll[0].Company;
}
else if(coll.Count >1)
{
// string name = coll[0].FirstName;
if (parameter.ToString() == "FName")
{
string name = coll[0].FirstName;
foreach (var c in coll)
{
if (c.FirstName != name)
return null;
else continue;
}
return name;
}
if (parameter.ToString() == "SName")
{
string name = coll[0].SecondName;
foreach (var c in coll)
{
if (c.SecondName != name)
return null;
else continue;
}
return name;
}
if (parameter.ToString() == "Comp")
{
string name = coll[0].Company;
foreach (var c in coll)
{
if (c.Company != name)
return null;
else continue;
}
return name;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter.ToString() == "FName")
{
foreach (var c in mycollection)
{
c.FirstName = value.ToString();
}
return mycollection;
}
else
if (parameter.ToString() == "SName")
{
foreach (var c in mycollection)
{
c.SecondName = value.ToString();
}
return mycollection;
}
else
if (parameter.ToString() == "Comp")
{
foreach (var c in mycollection)
{
c.Company = value.ToString();
}
return mycollection;
}
return null;
}
}
if (listUser.SelectedItems.Count > 1)
{
for (int i = 0; i < listUser.SelectedItems.Count; i++)
{
Info info = listUser.SelectedItems[i] as Info;
info.Note = (string)tbNote.Text;
}
}