MVVM:绑定到列表IsSelected同时跟踪IsSynchronizedWithCurrentItem [英] MVVM: Binding to List IsSelected while tracking IsSynchronizedWithCurrentItem

查看:98
本文介绍了MVVM:绑定到列表IsSelected同时跟踪IsSynchronizedWithCurrentItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被绑定到IsSelected跟踪一个MVVM设计的ListView选择更改。我还需要通过启用IsSynchronizedWithCurrentItem跟踪当前的项目。

我发现,当我有两个ListView控件绑定到同一集合我得到的出现InvalidOperationException 。集合被修改;枚举操作可能不会执行的这似乎是两个列表视图之间的控制同步误差;一个触发PropertyChanged事件而另一个可能更新选择?

我不知道如何解决这个问题除了放弃使用IsSynchronizedWithCurrentItem和管理它自己。任何想法?

感谢。

视图模型和$ C $背后C:

 公共类项目:INotifyPropertyChanged的
{
    公共字符串名称{;组; }    公共BOOL IsSelected
    {
        {返回isSelected; }
        集合{isSelected =价值; OnPropertyChanged(IsSelected); }
    }
    私人布尔isSelected;    公共事件PropertyChangedEventHandler的PropertyChanged;
    私人无效OnPropertyChanged(字符串propertyName的)
    {
        如果(的PropertyChanged!= NULL)
            的PropertyChanged(这一点,新PropertyChangedEventArgs(propertyName的));
    }
}公共类视图模型
{
    公共视图模型()
    {
        项目=新的ObservableCollection<项目>()
                {
                    新项目(){名称=富},
                    新项目(){名称=酒吧}
                };
    }
    公众的ObservableCollection<项目>项目{搞定;私人集; }
}公共部分类窗口1:窗口
{
    公共窗口1()
    {
        的InitializeComponent();
        的DataContext =新视图模型();
    }
}

的XAML:

 <窗​​口x:类=WpfApplication1.Window1
    的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
    的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
    标题=窗口1HEIGHT =100WIDTH =100>
    <&StackPanel的GT;
        < ListView控件的DataContext ={绑定表项}的ItemsSource ={结合}
                  IsSynchronizedWithCurrentItem =真的SelectionMode =单>
            < ListView.ItemContainerStyle>
                <风格的TargetType =ListViewItem的>
                    < setter属性=IsSelectedVALUE ={结合IsSelected,模式=双向}/>
                < /样式和GT;
            < /ListView.ItemContainerStyle>
            < ListView.ItemTemplate>
                <&DataTemplate的GT;
                    < TextBlock的文本={绑定路径=名称,模式=单向}/>
                < / DataTemplate中>
            < /ListView.ItemTemplate>
        < /&的ListView GT;
        < ListView控件的DataContext ={绑定表项}的ItemsSource ={结合}
              IsSynchronizedWithCurrentItem =真的SelectionMode =单>
            < ListView.ItemContainerStyle>
                <风格的TargetType =ListViewItem的>
                    < setter属性=IsSelectedVALUE ={结合IsSelected,模式=双向}/>
                < /样式和GT;
            < /ListView.ItemContainerStyle>
            < ListView.ItemTemplate>
                <&DataTemplate的GT;
                    < TextBlock的文本={绑定路径=名称,模式=单向}/>
                < / DataTemplate中>
            < /ListView.ItemTemplate>
        < /&的ListView GT;
    < / StackPanel的>
< /窗GT;


解决方案

我无法为你的问题的直接修复。不过,我有一个解决方案,将工作。

你可以做的是所谓的'的SelectedItem',将举行到在你的ListView选择的项目的引用您的视图模型引入了第二个属性。此外,在您的视图模型,你听PropertyChanged事件。如果关联的属性名称是IsSelected则进行更新SelectedItem属性是该事件(现在已IsSelected = true,则项目)的发送者。然后,您可以在ListView的SelectedItem属性绑定到ViewModel类的相同名称的属性。

我的code订正ViewModel类如下。

 公共类视图模型:INotifyPropertyChanged的
{
    私人项目_selectedItem;    公共视图模型()
    {
        项目=新的ObservableCollection<项目>()
            {
                新项目{名称=富},
                新项目{名称=酒吧}
            };        的foreach(在项目项目anItem)
        {
            anItem.PropertyChanged + = OnItemIsSelectedChanged;
        }
    }    公众的ObservableCollection<项目>项目{搞定;私人集; }    公共项目的SelectedItem
    {
        {返回_selectedItem; }
        组
        {
            //仅当值差更新,不
            //想送误报
            如果(_selectedItem ==值)
            {
                返回;
            }            _selectedItem =价值;
            OnPropertyChanged(的SelectedItem);
        }
    }    公共事件PropertyChangedEventHandler的PropertyChanged;    保护无效OnItemIsSelectedChanged(对象发件人,PropertyChangedEventArgs E)
    {
        如果(e.PropertyName!=IsSelected)
        {
            返回;
        }        的SelectedItem =发件人的项目;
    }    私人无效OnPropertyChanged(字符串propertyName的)
    {
        如果(的PropertyChanged!= NULL)
        {
            的PropertyChanged(这一点,新PropertyChangedEventArgs(propertyName的));
        }
    }
}

I'm tracking ListView selection changes in an MVVM design by binding to IsSelected. I also need to track the current item by enabling IsSynchronizedWithCurrentItem.

I find that when I have two ListView binding to the same collection I get the InvalidOperationException: "Collection was modified; enumeration operation may not execute." It seems to be a synchonization error between the two ListViews; one is triggering a PropertyChanged event while the other is updating the Selector perhaps?

I can't figure out how to get around this other than forgoing use of IsSynchronizedWithCurrentItem and managing it myself. Any ideas?

Thanks.

The ViewModel and code behind:

public class Item : INotifyPropertyChanged
{        
    public string Name{ get; set; }

    public bool IsSelected
    {
        get { return isSelected; }
        set { isSelected = value; OnPropertyChanged("IsSelected"); }
    }
    private bool isSelected;

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class ViewModel
{
    public ViewModel()
    {
        Items = new ObservableCollection<Item>()
                {
                    new Item(){Name = "Foo"},
                    new Item(){Name = "Bar"}
                };
    }
    public ObservableCollection<Item> Items { get; private set; }
}

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

The XAML:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="100" Width="100">
    <StackPanel>
        <ListView DataContext="{Binding Items}" ItemsSource="{Binding}" 
                  IsSynchronizedWithCurrentItem="True" SelectionMode="Single">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <ListView DataContext="{Binding Items}" ItemsSource="{Binding}" 
              IsSynchronizedWithCurrentItem="True" SelectionMode="Single">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackPanel>
</Window>

解决方案

I cannot offer a direct fix for your problem. However, I do have a solution that will work.

What you can do is introduce a second property on your View Model called 'SelectedItem' that will hold a reference to the Item that is selected in your ListView. In addition, in your View Model you listen for the PropertyChanged event. If the associated Property Name is IsSelected then you update the SelectedItem property to be the sender of that event (the Item that now has IsSelected = true). You can then bind the SelectedItem property of the ListView to the property of the same name of the ViewModel class.

My code for the revised ViewModel class is below.

public class ViewModel : INotifyPropertyChanged
{
    private Item _selectedItem;

    public ViewModel()
    {
        Items = new ObservableCollection<Item>()
            {
                new Item {Name = "Foo"},
                new Item {Name = "Bar"}
            };

        foreach ( Item anItem in Items )
        {
            anItem.PropertyChanged += OnItemIsSelectedChanged;
        }
    }

    public ObservableCollection<Item> Items { get; private set; }

    public Item SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            // only update if the value is difference, don't
            // want to send false positives
            if ( _selectedItem == value )
            {
                return;
            }

            _selectedItem = value;
            OnPropertyChanged("SelectedItem");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnItemIsSelectedChanged(object sender, PropertyChangedEventArgs e)
    {
        if ( e.PropertyName != "IsSelected" )
        {
            return;
        }

        SelectedItem = sender as Item;
    }

    private void OnPropertyChanged(string propertyName)
    {
        if ( PropertyChanged != null )
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

这篇关于MVVM:绑定到列表IsSelected同时跟踪IsSynchronizedWithCurrentItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆