Search code examples
c#itemscontroleventaggregator

Communication between Items in ItemsControl without using Messenger or EventAggregator


How can Items from Bindings in a ItemsControl communicate with each other without using Messenger, or EventAggregator. Below is a simplified yet complete case. Where I have two associated items in the ItemsControl. UpdateTheSecondItemFromTheFirstItem() can be done by using EventAggregator(messenger) in prism. But I'm wondering if there is any more direct solution to achieve this without using messenger. MainWindow:

    <Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
  <ItemsControl ItemsSource="{Binding MyItems}">
       <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
               <StackPanel Orientation="Vertical">
              </StackPanel>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
         <DataTemplate DataType="MyType">
            <Grid>
                <Slider Value="{Binding MyNum}" Minimum="0" Maximum="100"></Slider>
            </Grid>
         </DataTemplate>
        </ItemsControl.ItemTemplate>
  </ItemsControl>
</Grid>

MyType

   using Prism.Mvvm;

namespace WpfApp2
{
    public class MyType : BindableBase
    {
        private bool _isFirstItem=false;

        private int _myVar;

        public int MyVar
        {
            get { return _myVar; }
            set
            {
                if (Equals(_myVar, value)) return;
                SetProperty(ref _myVar, value);
            }
        }

        public MyType(bool isFirst)
        {
            _isFirstItem = isFirst;
            MyVar = 0;
        }
    }
}

MainWindowViewModel

    using Prism.Mvvm;
using System.Collections.ObjectModel;

namespace WpfApp2
{
    public class MainWindowViewModel:BindableBase
    {
        private ObservableCollection<MyType> _myItems = new ObservableCollection<MyType>();

        public ObservableCollection<MyType> MyItems
        {
            get { return _myItems; }
            set
            {
                if (Equals(_myItems, value)) return;
                SetProperty(ref _myItems, value);
                if(_isFirstItem) UpdateTheSecondItemFromTheFirstItem();
            }
        }

        private void UpdateTheSecondItemFromTheFirstItem(){

        }

        public MainWindowViewModel()
        {
            MyType[] MyTypeArr =
            {
                new MyType(true),
                new MyType(false)
            };
            MyItems.AddRange(MyTypeArr);
        }
    }
}

Solution

  • Found the solution, just use ref, which is exactly like pointer in C++:

    MainWindowViewModel:

            public MainWindowViewModel()
        {
            MyType Type1 = new MyType();
            MyType Type2 = new MyType();
    
            MyItems.Add(Type1);
            MyItems.Add(Type2);
    
            Type1.SetPair(ref Type2);
        }
    

    MyType.cs:

       using Prism.Mvvm;
    
    namespace WpfApp2
    {
        public class MyType : BindableBase
        {
            private int _myVar;
    
            public int MyVar
            {
                get { return _myVar; }
                set
                {
                    if (Equals(_myVar, value)) return;
                    SetProperty(ref _myVar, value);
                    if (MyPair!=null)
                    {
                        MyPair.MyVar = value;
                    }
                }
            }
    
            public MyType()
            {
                MyVar = 0;
            }
    
            MyType MyPair { get; set; }
    
            public void SetPair(ref MyType pair)
            {
                MyPair = pair;
            }
    
            public MyType GetPair()
            {
                return MyPair;
            }
        }
    }    
    

    Now, when dragging the slider, the second slider will move along with the first slider.