C# 如何在WPF中进行多项目数据绑定

C# 如何在WPF中进行多项目数据绑定,c#,wpf,xaml,mvvm,data-binding,C#,Wpf,Xaml,Mvvm,Data Binding,我有一个特殊的场景。我的应用程序看起来像这样 在左侧有一些用户列表,它是一个列表框,在右侧有几个字段,这些字段是绑定到左侧的数据。它的工作原理是,如果您在右侧选择“用户1”,将显示用户1相关信息,您可以修改该信息,并且其数据绑定为“UpdateSourceTrigger=PropertyChanged”,因此它也会立即反映在左侧。其他用户也是如此 现在的问题是,如果我选择多个用户并编辑一个字段,比如说字段3,它是可编辑的文本框。现在,如果我选择用户1并编辑此文本框,它将反映在用户1的“备注:…”

我有一个特殊的场景。我的应用程序看起来像这样

在左侧有一些用户列表,它是一个列表框,在右侧有几个字段,这些字段是绑定到左侧的数据。它的工作原理是,如果您在右侧选择“用户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;
    }
}