There's my project tree:
MRE_WPF
|
--ViewModels
|
--MainWindowButtons
|
--HomeButtonViewModel.cs
--UserSettingsButtonViewModel.cs
--MainWindow.xaml
--MainWindow.xaml.cs
I have three buttons on main window.
<Window x:Class="MRE_WPF.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:local="clr-namespace:MRE_WPF"
xmlns:main_window_buttons="clr-namespace:MRE_WPF.ViewModels.MainWindowButtons"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas Height="480" Name="MainCanvas">
<Button x:Name="homeButton"
Height="55"
Width="75"
Background="#FF334166"
Foreground="{x:Null}"
FontSize="24"
BorderBrush="{x:Null}"
FontFamily="Tahoma"
Canvas.Top="{Binding Path=(main_window_buttons:HomeButtonViewModel.CanvasTop), Mode=TwoWay, RelativeSource={RelativeSource Self}}"
>
<TextBlock Text="Home" Foreground="White"/>
</Button>
<Button x:Name="userSetingsButton"
Height="55"
Width="75"
Background="#FF334166"
Foreground="{x:Null}"
FontSize="20"
BorderBrush="{x:Null}"
FontFamily="Tahoma"
Canvas.Top="{Binding Path=(main_window_buttons:UserSettingsButtonViewModel.CanvasTop), Mode=TwoWay, RelativeSource={RelativeSource Self}}"
Canvas.Left="{Binding Path=(main_window_buttons:UserSettingsButtonViewModel.CanvasLeft), Mode=TwoWay, RelativeSource={RelativeSource Self}}"
>
<TextBlock Text="User set" Foreground="White"/>
</Button>
<Button x:Name="changeButton"
Height="55"
Width="75"
Background="#FF334166"
Foreground="{x:Null}"
FontSize="20"
Click="changeButton_Click"
BorderBrush="{x:Null}"
FontFamily="Tahoma"
Canvas.Top="100"
Canvas.Left="500">
<TextBlock Text="Change" Foreground="White"></TextBlock>
</Button>
</Canvas>
</Window>
HomeButtonViewModel
class:
public class HomeButtonViewModel:INotifyPropertyChanged {
public event PropertyChangedEventHandler? PropertyChanged;
private double canvasTop;
public double CanvasTop {
get => canvasTop;
set {
canvasTop = value;
OnPropertyChanged(nameof(CanvasTop));
}
}
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
UserSettingsButtonViewModel
is pretty much the same:
public class UserSettingsButtonViewModel:INotifyPropertyChanged {
public event PropertyChangedEventHandler? PropertyChanged;
private double canvasTop = 102;
private double canvasLeft = -1;
public double CanvasTop {
get => canvasTop;
set {
canvasTop = value;
OnPropertyChanged(nameof(CanvasTop));
}
}
public double CanvasLeft {
get => canvasLeft;
set {
canvasLeft = value;
OnPropertyChanged(nameof(canvasLeft));
}
}
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
I want to change those properties on click on button Change
:
private void changeButton_Click(object sender, RoutedEventArgs e) {
bool mode = !(bool)Settings.Default["mode7"];
Settings.Default["mode7"] = mode;
Settings.Default.Save();
var h = new HomeButtonViewModel() {
CanvasTop = mode ? 1 : 0
};
var us = new UserSettingsButtonViewModel() {
CanvasTop = mode ? 102 : double.NaN,
CanvasLeft = mode ? -1 : double.NaN
};
}
But on click nothing happens. I know that I do something wrong, but I don't know what.
//Also I want use command instead of Click, but let's solve one problem per question.
It's unclear why you have two view models.
Anyway, you should set the DataContext
of the window to an instance of a single view model. In this once you could then initialize the child view models:
public class MainWindowVieModel
{
public HomeButtonViewModel HomeButtonViewModel { get; }
= new HomeButtonViewModel();
public UserSettingsButtonViewModel UserSettingsButtonViewModel { get; }
= new UserSettingsButtonViewModel();
}
You could then bind to the child view models through the main view model/DataContext
in the view using the following syntax:
<Button x:Name="homeButton"
Height="55"
Width="75"
Background="#FF334166"
Foreground="{x:Null}"
FontSize="24"
BorderBrush="{x:Null}"
FontFamily="Tahoma"
Canvas.Top="{Binding HomeButtonViewModel.CanvasTop}"
>
<TextBlock Text="Home" Foreground="White"/>
</Button>
<Button x:Name="userSetingsButton"
Height="55"
Width="75"
Background="#FF334166"
Foreground="{x:Null}"
FontSize="20"
BorderBrush="{x:Null}"
FontFamily="Tahoma"
Canvas.Top="{Binding UserSettingsButtonViewModel.CanvasTop}"
Canvas.Left="{Binding UserSettingsButtonViewModel.CanvasLeft}"
>
<TextBlock Text="User set" Foreground="White"/>
</Button>
Finally, you need to set the properties of the view model instance(s) that you actually bind to in the code-behind of the window (where you should also set the DataContext
of the window):
public partial class MainWindow : Window
{
private readonly MainWindowVieModel _viewModel = new MainWindowVieModel();
public MainWindow()
{
InitializeComponent();
DataContext = _viewModel;
}
private void changeButton_Click(object sender, RoutedEventArgs e)
{
bool mode = !(bool)Settings.Default["mode7"];
Settings.Default["mode7"] = mode;
Settings.Default.Save();
_viewModel.HomeButtonViewModel.CanvasTop = mode ? 1 : 0;
_viewModel.UserSettingsButtonViewModel.CanvasTop = mode ? 102 : double.NaN;
_viewModel.UserSettingsButtonViewModel.CanvasLeft = mode ? -1 : double.NaN;
}
}