简体   繁体   English

如何执行多个项目WPF中的数据绑定

[英]How to do multiple items Data binding in WPF

I have a particular scenarios. 我有一个特殊的场景。 My application looks like this. 我的应用程序如下所示。 在此处输入图片说明

In the left side there are some User list Which is a ListBox and at the right side few fields which are data binding to left side. 左侧有一些用户列表,它是一个列表框,右侧有一些字段,这些字段将数据绑定到左侧。 How it works is, if you select "User 1" in the right side user 1 related information will appear and you can modify the information and its is data binding with "UpdateSourceTrigger=PropertyChanged" so it immediately reflects at the left side too. 它是如何工作的,如果您在右侧选择了“用户1”,则将出现与用户1相关的信息,您可以修改该信息,并且其数据绑定是"UpdateSourceTrigger=PropertyChanged"因此它也立即反映在左侧。 Same case for other users. 其他用户也是如此。

Now the problem is if I select multiple users and edit a field say Field 3 which is Editable a textBox. 现在的问题是,如果我选择多个用户并编辑一个字段,说“字段3”是“可编辑的文本框”。 Now If I select user 1 and edit this textbox it reflects in the user 1 "Note: ... " and if I select user 2 and edit the Field 3 it updates the User 2 "Note: ... " but in case of multi selection How do I achieve it? 现在,如果我选择用户1并编辑此文本框,它将反映在用户1“注:...”中;如果我选择用户2并编辑字段3,它将更新用户2“注:...”,但如果多重选择如何实现? Suppose I want to select user 1 and User 2 both and Edit the Note field It should update both the note fields of user 1 and user 2 and Data binding should also work I mean it should immediately the text i am entering into the textbox. 假设我要同时选择用户1和用户2并编辑“注释”字段它应该同时更新用户1和用户2的注​​释字段,并且数据绑定也应该起作用,这意味着它应该立即将我输入的文本输入文本框。 Any ideas how can I achieve this? 有什么想法可以实现吗?

Currently in my viewModel 目前在我的viewModel中

Model 模型

public String Note
        {
            get
            {
                return (String)GetValue(NoteProperty);
            }
            set { SetValue(NoteProperty, value); }
        }

View 视图

and in XAML the User ListBox Items template is defined like this 在XAML中,User ListBox Items模板的定义如下

<TextBlock Text="{Binding Note, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

and in the XAML the rightside textbox (field 3) is data bound in the same manner 在XAML中,右侧文本框(字段3)是以相同方式绑定数据的

<TextBox Text="{Binding Note, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"  />

How do I achieve multiple users data binding? 如何实现多个用户的数据绑定?

Please help and give me some ideas. 请帮忙,给我一些想法。

EDIT: 编辑:

Converter: 转换器:

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;
    }
}

For me only one TextBox Editable NoteTextBox needs to to be DataBinded with multiple Users. 对我来说,只有一个TextBox Editable NoteTextBox需要与多个用户进行数据绑定。

In my ViewModel 在我的ViewModel中

I have written 我已经写了

ViewModel 视图模型

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");
            }
        }

In the Info class there is one property Note which needs to be binded to the View's two places. Info类中,有一个属性Note ,它需要绑定到View的两个位置。

I fully agree with @GazTheDestroyer ... this kind of Data Binding can not be achieved through Data binding alone. 我完全同意@GazTheDestroyer ...这种数据绑定无法仅通过数据绑定来实现。 What @Kumar has suggested is working as a POC, but when you are in a live project and you play with model, viewModel and view and many UserControl with one view model or one User control with two ViewModels, then the difficulty of achieving this scenario is beyond guessing. @Kumar提出的建议是充当POC,但是当您在一个实时项目中并使用模型,viewModel和视图以及许多具有一个视图模型的UserControl或一个具有两个ViewModels的用户控件时,那么实现这种情况就很困难无法猜测。

Ok, no more theory. 好的,不再有理论了。 I have achieved this and I am going to share how I did so. 我已经实现了这一目标,我将分享如何实现这一目标。

One-to-one DataBinding is perfect and working fine. 一对一的数据绑定是完美的并且可以正常工作。 When you select User 4 This user Note field and Field3 Editable NoteBox are bound to the same Property, so it works perfectly. 当您选择用户4时,此用户Note字段和Field3 Editable NoteBox绑定到相同的属性,因此可以完美工作。

In multiple selection say User4 is selected first, then you select User3 and user1 , I put a logic in code behind that when multiple items are selected Note text is empty. 在多项选择中,说首先选择了User4 ,然后选择了User3user1 ,然后在代码中添加了逻辑,即当选择了多个项目时, Note文本为空。 This is not against MVVM as updating a view based on some criteria of view is not breaking MVVM pattern. 这不反对MVVM,因为基于某些视图标准更新视图不​​会破坏MVVM模式。 So now when the editable text box is updated with some text user4 properties is updated in viewModel. 当编辑文本框与一些文本更新所以现在user4性能在视图模型进行更新。 Now the difficult part is to update the other selected users. 现在,困难的部分是更新其他选定的用户。 Here is the code that will update the selected users and will reflect as I have mentioned Mode="TwoWay", UpdateSourceTriger="PropertyChanged" 这是将更新所选用户并反映出我所提及的Mode="TwoWay", UpdateSourceTriger="PropertyChanged"

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;
    }
}

In this way the value of the Editable note textbox is updated in the properties of all the users Note Property and as the binding is two-way, it will reflect in other users too. 这样, Editable note textbox值将在所有用户的“ Note Property的属性中更新,并且由于绑定是双向的,因此它也会在其他用户中反映出来。

There might be many way to solve it, but I found this way and it's working superbly, so I thought I'd answer my own question. 解决它的方法可能很多,但是我发现了这种方法,而且效果很好,所以我想我会回答自己的问题。

You cannot achieve this via databinding alone, since there are situations where you need to make logical decisions. 您不能仅通过数据绑定来实现此目的,因为在某些情况下需要做出逻辑决策。

For instance, if user1 and user2 have different notetext, then when both are selected you cannot show both at the same time. 例如,如果user1和user2具有不同的注释文本,则当两者都被选中时,您将无法同时显示两者。 Instead I guess you want some method of specifying that you want to "keep original text", or allow user to over type to set both texts to be the same. 相反,我猜您想使用某种方法来指定要“保留原始文本”,或者允许用户改写以将两个文本设置为相同。

Whatever you intend, you need to have separate binding sources in your viewmodel so that you can update them independently and make logical decisions. 无论您打算做什么,都需要在视图模型中拥有单独的绑定源,以便可以独立更新它们并做出合理的决定。

I tried something with i know and i got output just as your requirement.Please correct me if i'm wrong. 我尝试了一些我知道的事情,并且按照您的要求得到了输出。如果我错了,请更正我。

XAML

<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>

C#

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new ViewModel();
            }

        }

Model 模型

        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));
                }
            }
        }

ViewModel 视图模型

        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
        }

Converter 转换器

        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;
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM