Answer the question
In order to leave comments, you need to log in
How to link a specific shape to a selected element?
The viewmodel contains a collection of four models. There are four lines in the view. How to change the color of the line depending on the selected model? If the first model is chosen, then the color of the first line changes from blue to red. The second pattern is selected -- the second line turns red, the first line turns blue again.
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>
Answer the question
In order to leave comments, you need to log in
While there is no opportunity to write an example, but I will try to supplement the answer when it appears.
If the number of displayed elements is not too large (in the range of 100-1000), then it is probably best to move some of the information into the ViewModel (namely, the coordinates of the lines and the IsSelected state ). In your example, this class is named Model, but I recommend renaming it, it can be confusing later on.
Then you will bind the collection to the ItemsControl , where the panel will be the Canvas.
Bind coordinates individually. It will be possible to react to a color change either through a trigger or through a converter, but if there are only 2 options, then it will be easier, in my opinion, to use the trigger.
When selecting an element in the collection, reset the IsSelected state of the previous element to False and set the specified value to True .
There are a few free minutes, I give an example:
To begin with, for convenience, let's create ViewModelBase so as not to implement the INPC interface several times :
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;
}
}
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; }
}
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)
};
}
}
<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>
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question