1

Let's say I have 12 rectangles defined in a XAMl page like this:

<Rectangle x:Name="C" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="10,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="D" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="78,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="E" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="146,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="F" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="214,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="G" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="281,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="A" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="347,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="B" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="226" Margin="414,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>
<Rectangle x:Name="CSh" Fill="Black" HorizontalAlignment="Left" Height="121" Margin="47,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="63"/>
<Rectangle x:Name="DSh" Fill="Black" HorizontalAlignment="Left" Height="121" Margin="115,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="62"/>
<Rectangle x:Name="FSh" Fill="Black" HorizontalAlignment="Left" Height="121" Margin="249,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="63"/>
<Rectangle x:Name="GSh" Fill="Black" HorizontalAlignment="Left" Height="121" Margin="317,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="63"/>
<Rectangle x:Name="ASh" Fill="Black" HorizontalAlignment="Left" Height="121" Margin="385,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="63"/>

How can I change the color of a specific rectangle from ViewModel without using CodeBehind?

EXAMPLE: If I press the key "A" on my keyboard the element in my xaml page named "A" has to be colored with green, if I press "B" on my keyboard the element named "B" on my XAML have to be colored in green and so on.

I already have some basic understanding on how binding works, but I can't find any solution around, can anyone point me in the right direction?

FabioEnne
  • 732
  • 1
  • 14
  • 43
  • Hi, can you post what you have tried? You didn't even try to bind Fill property to anything in your viewmodel. – Natxo Feb 27 '20 at 16:07
  • @Natxo I didn't post anything related to the binding as I don't really know ho to bind something by the object name.. – FabioEnne Feb 27 '20 at 16:09
  • If you want to handle a pressed key and use it to find the Rectangle by name, then you must use codebehind. There is nothing wrong with doing so in mvvm. – Natxo Feb 27 '20 at 16:17
  • Do write a behavior, which is listening for key down and evaluate it. You can then __manage in XAML__ to use or not to use this behavior for a particular element. – Rekshino Feb 27 '20 at 16:31
  • @Rekshino thanks for the replay, can please provide some lines of code as an example as an answer? Many Thanks – FabioEnne Feb 27 '20 at 16:48
  • You've already asked the [same question](https://stackoverflow.com/questions/60435992/wpf-mvvm-how-to-change-item-property-by-item-name) – Pavel Anikhouski Feb 27 '20 at 18:08
  • Does this answer your question? [WPF MVVM How to change item property by item name?](https://stackoverflow.com/questions/60435992/wpf-mvvm-how-to-change-item-property-by-item-name) – Pavel Anikhouski Feb 27 '20 at 18:09
  • @PavelAnikhouski yes, a moderator, said it was a duplicate of https://stackoverflow.com/questions/12238599/find-wpf-control-by-name this one (not MVVM pattern related), and closed my question. – FabioEnne Feb 28 '20 at 07:54
  • I have posted an example as an answer. – Rekshino Feb 28 '20 at 09:42

2 Answers2

0

First u need to add this to ur xaml code

<Rectangle x:Name="C" Fill="{Binding Color}" HorizontalAlignment="Left" Height="226" Margin="10,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="69"/>

next u need to create ViewModel

publuc MyViewModel() :INotifyPropertyChanged
{
        Brush _color;
        Brush Color{get{return _color;} set{_color = value; OnPropertyChanged("Color")}}

  public MyViewModel()
  {
      Color = Brushes.Green;
  }
}

and on the end add in your xaml.cs class of your window

DataContext = new DERDashboardUserControlViewModel();

U can add button around your Rectangle and create command that will bind to method in your View Model. Here is link how to do taht How to bind WPF button to a command in ViewModel

Filip Filipovic
  • 410
  • 3
  • 13
  • thanks for the replay, but that's gonna change all the rectangles Binded with the property "Color", I need to set just a specific one, let's say, for example, only the rectangle named "x:Name="Dsh", not every rectangles. – FabioEnne Feb 28 '20 at 07:51
  • U can create dictionary with key to be x:Name and value to be Brush, when u call your method pass x:Name as parameter and then just change one brush from dictionary – Filip Filipovic Feb 28 '20 at 08:37
  • You shouldn't refer a presentationframework.dll in ViewModel. – Rekshino Feb 28 '20 at 08:42
0

This is a behavior for Window:

using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Shapes;

public class ListenKeyBehavior : Behavior<Window>
{
    public Brush KeyBgBrush { get; set; }
    private Brush _originalBgBrush;

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
        AssociatedObject.PreviewKeyUp += AssociatedObject_PreviewKeyUp;
    }

    private void AssociatedObject_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        var foundEl = GetChildByName(AssociatedObject, e.Key.ToString().ToLower()) as Shape;
        if (foundEl != null && KeyBgBrush != null && _originalBgBrush==null)
        {
            _originalBgBrush = foundEl.Fill;
            foundEl.Fill = KeyBgBrush;
        }
    }

    private void AssociatedObject_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        var foundEl = GetChildByName(AssociatedObject, e.Key.ToString().ToLower()) as Shape;
        if (foundEl != null && _originalBgBrush != null)
        {
            foundEl.Fill = _originalBgBrush;
            _originalBgBrush = null;
        }
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewKeyDown -= AssociatedObject_PreviewKeyDown;
        AssociatedObject.PreviewKeyUp -= AssociatedObject_PreviewKeyUp;
        base.OnDetaching();
    }
    public static object GetChildByName(DependencyObject depObj, string searchedName) 
    {
        if (depObj == null)
        {
            return null;
        }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);
            if (child is FrameworkElement childFrmWrkEl && childFrmWrkEl.Name.ToLower()==searchedName)
            {
                return child;
            }
            var result = GetChildByName(child, searchedName);
            if (result != null)
            {
                return result;
            }
        }
        return null;
    }
}

Apply this behavior to the Window:

<Window ..... xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
    <i:Interaction.Behaviors>
        <local:ListenKeyBehavior KeyBgBrush="Green" />
    </i:Interaction.Behaviors>
    .....
</Window>
Rekshino
  • 6,954
  • 2
  • 19
  • 44