@toSteel

Как связать конкретную фигуру с выбранным элементом?

Во вьюмодели коллекция из четырех моделей. В представлении четыре линии. Как менять цвет линии в зависимости от выбранной модели ? Если выбрали первую модель, то цвет первой линии меняется с синего на красный. Выбрана вторая модель -- вторая линия становится красной, первая опять синей.

public class Model : INotifyPropertyChanged
        {
            private string name;


            public string Name
            {
                get { return name; }
                set
                {
                    name = value;
                    OnPropertyChanged("Name");
                }
            }


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


 public class ViewModel : INotifyPropertyChanged
    {
        private Model selectedModel;

        public ObservableCollection<Model> Models { get; set; }
        public Model SelectedModel
        {
            get { return selectedModel; }
            set
            {
                selectedModel = value;
                OnPropertyChanged("SelectedModel");
            }
        }

        public ViewModel()
        {
            Models = new ObservableCollection<Model>
            {
                new Model { Name="A" },
                new Model {Name="B", },
                new Model {Name="C" },
                new Model {Name="D" }
            };
        }

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

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0.8*" />
            <ColumnDefinition Width="0.8*" />
        </Grid.ColumnDefinitions>

        <ListBox
            Grid.Column="0"
            ItemsSource="{Binding Models}"
            SelectedItem="{Binding SelectedModel}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBlock FontSize="18" Text="{Binding Path=Name}" />

                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <StackPanel Grid.Column="1" DataContext="{Binding SelectedModel}">
            <TextBlock Text="Выбранный элемент" />
            <TextBlock Text="Модель" />
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />

        </StackPanel>
        <Canvas Grid.Column="2">
            <Line
                Canvas.Left="10"
                Canvas.Top="20"
                Stroke="Red"
                X1="0"
                X2="100"
                Y1="0"
                Y2="00" />
            <Line
                Canvas.Left="10"
                Canvas.Top="40"
                Stroke="Blue"
                X1="0"
                X2="100"
                Y1="0"
                Y2="00" />
            <Line
                Canvas.Left="10"
                Canvas.Top="60"
                Stroke="Blue"
                X1="0"
                X2="100"
                Y1="0"
                Y2="00" />
            <Line
                Canvas.Left="10"
                Canvas.Top="80"
                Stroke="Blue"
                X1="0"
                X2="100"
                Y1="0"
                Y2="00" />

        </Canvas>
    </Grid>
  • Вопрос задан
  • 108 просмотров
Решения вопроса 1
FoggyFinder
@FoggyFinder
Пока нет возможности написать пример, но попробую дополнить ответ когда она появится.

Если количество отображаемых элементов не слишком большое (в пределах 100-1000), то, вероятно, лучшим вариантом будет вынести часть информации в ViewModel (а именно, координаты расположения линий и состояние IsSelected). В вашем примере этот класс назван Model, но я рекомендую его переименовать, в дальнейшем это может сбить с толку.

Тогда вы привяжите коллекцию к ItemsControl, где панелью будет выступать Canvas.
Координаты привяжите индивидуально. Реагировать на изменение цвета можно будет или через триггер или через конвертер, но если вариантов всего 2, то проще, на мой взгляд, будет использовать именно триггер.

При выделении элемента в коллекции сбрасываете состояние IsSelected предыдущего элемента в False и указанному соответственно ставите True.

Обновлено:

Появились несколько свободных минут, привожу пример:

Для начала, для удобства создадим ViewModelBase, чтобы несколько раз не реализовывать интерфейс INPC:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<T>.Default.Equals(storage, value))
            return false;
        storage = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }
}


Теперь, как я уже писал выше, нам понадобиться отдельная ViewModel для ячейки, элемента списка:

public class LineVM : ViewModelBase
{
    private bool isSelected;
    public bool IsSelected
    {
        get { return isSelected; }
        set { SetProperty(ref isSelected, value); }
    }

    public LineVM(string name, int x, int y)
    {
        Name = name;
        X = x;
        Y = y;
    }
    public string Name { get; set; }

    public int X { get; private set; }

    public int Y { get; private set; }
}


Здесь нет необходимости в изменении координат во время работы программы, поэтому сеттеры оставим приватными.

Главная ViewModel :

public class ItemsVM : ViewModelBase
{
    private LineVM selectedVM;

    public ObservableCollection<LineVM> Models { get; }
    public LineVM SelectedModel
    {
        get { return selectedVM; }
        set
        {
            if (SelectedModel != null)
                SelectedModel.IsSelected = false;
            value.IsSelected = true;
            SetProperty(ref selectedVM, value);
        }
    }

    public ItemsVM()
    {
        Models = new ObservableCollection<LineVM>
        {
            new LineVM ("A", 10, 20 ),
            new LineVM ("B", 10, 40),
            new LineVM ("C", 10, 60),
            new LineVM ("D", 10, 80)
        };
    }
}


я не стал заниматься переименовыванием, но лучше, конечно, чтобы свойства отображали реальное назначение.

Теперь View часть. Привожу только измененный третий столбец:

<ItemsControl Grid.Column="2" ItemsSource="{Binding Models}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Line
            X1="0"
            X2="100"
            Y1="0"
            Y2="00">
                <Line.Style>
                    <Style TargetType="Line">
                        <Setter Property="Stroke" Value="Blue" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                <Setter Property="Stroke" Value="Red" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Line.Style>
            </Line>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding X}" />
            <Setter Property="Canvas.Top" Value="{Binding Y}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>


Тут тоже все достаточно просто - триггер реагирует на изменение свойства IsSelected и меняет цвет на красный для текущего элемента.

И, для наглядности, оставляю гифку:

5dd6e7e03664e626729135.gif
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы