1

I'm making a WPF application on MVVM pattern, where the user clicks the items of a tree (hyperlinks consisting of color names, the name text having the respective foreground) to change the background of the whole window. I am doing this through a relay command, but the UI is not acceptable in the View Model, where I am writing the command.

The tree with Color Names in XAML:

<TreeView Name="tree" ItemSource="{Binding colorList, Mode=TwoWay}" Background="Transparent">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemSource={Binding Children}>
             <TextBlock><Hyperlink Command={Binding ColorChangerCommand} Foreground={Binding Foreground} TextDecorations="None"><TextBlock Text={Binding Name}/></Hyperlink></TextBlock>
        </HierarchicalDataTemplate>
     </TreeView.ItemTemplate>
 <TreeView>

The Command in my View Model:

public RelayCommand ColorChangerCommand{ get; set;}

public TreeViewModel() //Constructor of the View Model
{
   ColorChangerCommand= new RelayCommand(ChangeColor);
}

public void ChangeColor(object sender)
{
  this.Background= (sender as TreeViewItem).Foreground;
}

The command was working fine in simple code-behind, but now not in the View Model. Help please?

8
  • Can you show your binding statement . in Xaml you are binding foregorund but in ViewModel property is named as Background Commented Mar 15, 2019 at 6:40
  • @PraveenM The foreground in Xaml is just simply the foreground of the text that has to be shown. For Example, the first item is "RED" with Red color as it's foreground. In the command in ViewModel, I'm getting the foreground of the clicked item, as setting it as the background of the window. For Example, If RED is clicked, the background of the Window becomes Red too. Commented Mar 15, 2019 at 7:08
  • when using a commands the object that you get in your ChangeColor-function is not the sender. This only works in events! What you should do is take a look at XAML triggers so you can solve your issue the way it was intended to be handled in WPF Commented Mar 15, 2019 at 7:35
  • I agree that this is a bit of a predicament that you're in, but consider following: Return a string from your view model i.e colour you want for the foreground and use a converter in UI to create a SolidColorBrush. Hope this helps Commented Mar 15, 2019 at 8:12
  • There should be a view model item class that represents the data of an individual TreeViewItem. That class should have a Color or Brush property for the Background color, which is modified by the command. In the TreeView's ItemContainerStyle, bind the TreeViewItem's Background to this view model property. Commented Mar 15, 2019 at 8:49

2 Answers 2

1

this.Background refers to the Background property of your view model provided that the ChangeColor method belongs to the view model class. For the window's background to change, you need to bind it to the Background property of the view model and raise an event to tell the UI to update. This requires your view model to implement the INotifyPropertyChanged event:

public class ViewModel : INotifyPropertyChanged
{
    public RelayCommand ColorChangerCommand { get; set; }

    public TreeViewModel() //Constructor of the View Model
    {
        ColorChangerCommand = new RelayCommand(ChangeColor);
    }

    public void ChangeColor(object sender)
    {
        this.Background = (sender as TreeViewItem).Foreground;
    }

    private Brush background= Brushes.White;
    public Brush Background
    {
        get { return background; }
        set { Background = value; NotifyPropertyChanged(Background); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML:

<Window .... Background="{Binding Background}" />

You also need to set the DataContext of the window to an instance of your view model class and bind the Command property of the Hyperlink like this:

<Hyperlink Command="{Binding DataContext.ColorChangerCommand, RelativeSource={RelativeSource AncestorType=Window}}" 
           Foreground="{Binding Foreground}" TextDecorations="None">
Sign up to request clarification or add additional context in comments.

8 Comments

public void ChangeColor(object sender) { this.Background = (sender as TreeViewItem).Foreground; } The sender is returning null here
@BellaSwan: Bind the CommandParameter of the Hyperlink to the TreeViewItem: CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}}".
Now the background is going black on clicking every item, instead of changing to the respective color. :(
What is the "respective color", i.e. where do you set the Foreground colour of the TreeViewItem? Does the binding work?
Yes, it does. When I created the list for the tree view items, I added the foreground and the name, then bound it in the XAML. For example, the word RED is being shown in red color. So when I click on it, being the sender, shouldn't it give it's foreground color to the Background, which is red?
|
0

Don't do it via ViewModel. UI belongs to the View. Use a behavior for it.

If you bind ForwardedColor to any other UI control, then you will change the bound property of this control, so you can easily manage it in XAML.

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TextBlock Text="Test" Foreground="Aquamarine">
    <i:Interaction.Behaviors>
        <local:ForwardForegroundOnClick  ForwardedColor="{Binding Background, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/>
    </i:Interaction.Behaviors>
</TextBlock>

public class ForwardForegroundOnClick : Behavior<TextBlock>
{
    public Brush ForwardedColor
    {
        get { return (Brush)GetValue(ForwardedColorProperty); }
        set { SetValue(ForwardedColorProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ForwardedColorProperty =
        DependencyProperty.Register(nameof(ForwardedColor), typeof(Brush), typeof(ForwardForegroundOnClick), new PropertyMetadata(null));

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
    }

    private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        ForwardedColor = AssociatedObject.Foreground;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;

        base.OnDetaching();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.