如何刷新多重绑定

时间:2013-10-07 07:29:35

标签: wpf mvvm

在列表框中我有带复选框的项目,在TextBlock中我想更新计数器,显示当前检查了多少个。 简单的场景,但我在刷新计数器的绑定方面遇到了问题。

我的xaml:

<Window x:Class="ListboxWithCounting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:ListboxWithCounting"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <vm:MyViewModel />
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate x:Key="CheckBoxListItem">
            <Border x:Name="CheckBoxItemElement" 
                    Background="Transparent" 
                    Padding="0,2,0,2">
                <CheckBox Content="{Binding Name}" 
                          IsChecked="{Binding Path=IsChecked,Mode=TwoWay,
                    UpdateSourceTrigger=PropertyChanged}"/>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBlock Grid.Column="1">
            <TextBlock.Text>
                <MultiBinding StringFormat="Items checked: {0} of {1}">
                    <Binding Path="ColumnsChecked" />
                    <Binding Path="ColumnsCount" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>

        <ListBox ItemTemplate="{StaticResource CheckBoxListItem}" 
                         x:Name="Columns" 
                         ItemsSource="{Binding Columns}" />
    </Grid>
</Window>

我的视图模型和单个项目:

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

        private bool isChecked;
        public bool IsChecked
        {
            get
            {
                return isChecked;
            }
            set
            {
                isChecked = value;
                PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }

    public class MyViewModel
    {
        public int ColumnsCount
        {
            get
            {
                return Columns.Count;
            }
        }

        public int ColumnsChecked
        {
            get
            {
                return Columns.Where(x => x.IsChecked).Count();
            }
        }

        public List<Item> Columns
        {
            get
            {
                var data = new List<Item>()
                {
                    new Item(){ Name = "Item1", IsChecked=true },
                    new Item(){ Name = "Item2" },
                    new Item(){ Name = "Item3" }
                };

                data.ForEach(x => x.PropertyChanged += (s, e) => { });

                return data;
            }
        }
    }

如果更改列表状态中的每个复选框,如何触发多重绑定?

[UPDATE]

感谢slugster,工作代码:

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

        private bool isChecked;
        public bool IsChecked
        {
            get
            {
                return isChecked;
            }
            set
            {
                if (isChecked != value)
                {
                    isChecked = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }

    public class MyViewModel : INotifyPropertyChanged
    {
        public int ColumnsCount
        {
            get
            {
                return Columns.Count;
            }
        }

        public int ColumnsChecked
        {
            get
            {
                return Columns.Where(x => x.IsChecked).Count();
            }
        }

        private List<Item> columns;
        public List<Item> Columns
        {
            get
            {
                if (columns == null)
                {
                    columns = new List<Item>()
                    {
                        new Item(){ Name = "Item1", IsChecked=true },
                        new Item(){ Name = "Item2" },
                        new Item(){ Name = "Item3" }
                    };
                }

                columns.ForEach(x =>
                {
                    x.PropertyChanged -= x_PropertyChanged;
                    x.PropertyChanged += x_PropertyChanged;
                });

                return columns;
            }
        }

        void x_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("ColumnsChecked"));
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }

1 个答案:

答案 0 :(得分:2)

您的viewmodel还需要实现INotifyPropertyChanged,以便可以使绑定知道列表项的属性更改。

说实话,我不能告诉你是否只通知一个属性会导致整个多重绑定被评估(无论如何你可以快速找到),但是你可能想要通知任何其他绑定的两个属性。

public class MyViewModel : INotifyPropertyChanged
{

    [...snip...]

    public List<Item> Columns
    {
        get
        {
            var data = new List<Item>()
            {
                new Item(){ Name = "Item1", IsChecked=true },
                new Item(){ Name = "Item2" },
                new Item(){ Name = "Item3" }
            };

            data.ForEach(x => x.PropertyChanged += (s, e) => {       
                                                                OnPropertyChanged("ColumnsCount");
                                                                OnPropertyChanged("ColumnsChecked");
                                                             });

            return data;
        }
    }

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

    public event PropertyChangedEventHandler PropertyChanged;

}