SizeToContent disables EventTrigger - c#

I'm trying to make window size same as content, but when I use SizeToContent, it for some reason breaks my EventTrigger and it no longer invokes the command when the window is loaded.
Code sample:
WindowView:
<Window x:Class="Tasks.Views.TasksWindow"
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:Tasks.Views"
xmlns:ViewModels="clr-namespace:Tasks.ViewModels"
xmlns:Views="clr-namespace:Tasks.Views"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
SizeToContent="WidthAndHeight"
mc:Ignorable="d"
Title="TasksWindow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadTasksCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Window.DataContext>
<ViewModels:TasksViewModel/>
</Window.DataContext>
<Views:TasksControl/>
</Window>
ViewModel:
public class TasksViewModel : ObservableObject
{
private readonly ObservableCollection<TaskModel> _tasks
= new ObservableCollection<TaskModel>();
public IEnumerable<TaskModel> Tasks
{
get { return _tasks; }
}
public ICommand LoadTasksCommand
{
get { return new DelegateCommand(LoadTasks); }
}
public void LoadTasks()
{
string directory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string filePath = Path.Combine(directory, "Tasks.xml");
// Check if save file exists
if (!File.Exists(filePath))
return;
XmlSerializer xs = new XmlSerializer(typeof(TaskList));
using (StreamReader reader = new StreamReader("Tasks.xml"))
{
TaskList results = (TaskList)xs.Deserialize(reader);
foreach (var item in results.TasksList)
_tasks.Add(item);
}
}
}
Base:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
DelegateCommand:
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action) { _action = action; }
public void Execute(object parameter) { _action(); }
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
}
Model:
[XmlRoot("ArrayOfTaskModel")]
public class TaskList
{
[XmlElement("TaskModel")]
public List<TaskModel> TasksList { get; set; }
}
[Serializable]
public class TaskModel : ObservableObject
{
private string _name;
[XmlElement("Name")]
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChangedEvent("Name");
}
}
}

Related

get Variable from running Task and display on View

The code below executes fine when MyActionFunc is called but not when the function is in another class. MessageBox displays the correct string but it is not shown on view. What I am missing?
class ViewModel : INotifyPropertyChanged
{
public MyCommand ActionCommand
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public ViewModel()
{
ActionCommand = new MyCommand();
ActionCommand.CanExecuteFunc = obj => true;
// ActionCommand.ExecuteFunc = MyActionFunc;
ActionCommand.ExecuteFunc = MyClass.MyActionFunc;
}
private string myname;
public string myName
{
get => myname;
set { myname = value;; OnPropertyChanged(); }
}
public void MyActionFunc(object parameter)
{
myName = "Fred";
}
}
class MyClass
{
public static void MyActionFunc(object parameter)
{
ViewModel name = new ViewModel();
name.myName = "Fred";
MessageBox.Show(name.myName);
}
}
... and the binding to the Textbox
<TextBox Name="textBox" Grid.Column="1" Grid.Row="1" Text="{Binding Path=myName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>

WPF MVVM Switching Between Usercontrols

I am new to MVVM. I found this artcle and it resolve my haf of problems.
https://social.technet.microsoft.com/wiki/contents/articles/30898.simple-navigation-technique-in-wpf-using-mvvm.aspx
However, I need to navigate from one usercontrol to another from the button click event of one usercontrol not from the button on the main window.
Usercontrol 1:
Usercontrol 2:
This is what I have tried sofar;
class Usercontrol1ViewModel : INotifyPropertyChanged
{
public ICommand navCommand { get; set; }
public Usercontrol1ViewModel()
{
navCommand = new BaseCommand(navigate);
}
private void navigate(object obj)
{
NavigationViewModel mainViewModel = new NavigationViewModel();
mainViewModel.SelectedViewModel = new Usercontrol2ViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
NavigationView model class
Class NavigationViewModel : INotifyPropertyChanged
{
public ICommand btn1Command { get; set; }
public ICommand btn2Command { get; set; }
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set { selectedViewModel = value; OnPropertyChanged("SelectedViewModel"); }
}
public NavigationViewModel()
{
btn1Command = new BaseCommand(Opencontrl1);
btn2Command = new BaseCommand(Opencontrl2);
}
private void Opencontrl1(object obj)
{
SelectedViewModel = new Usercontrol1ViewModel();
}
private void Opencontrl2(object obj)
{
SelectedViewModel = new Usercontrol2ViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
Main window code behind;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new NavigationViewModel();
}
}
Can somebody guide me how to achieve this with MVVM?
Try the below code. I used the sample code in the article and I am the author of the MSDN article :)
MainWindow.xaml
<Window.Resources>
<DataTemplate DataType="{x:Type local:EmployeeViewModel}">
<local:EmployeeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:DepartmentViewModel}">
<local:DepartmentView/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
</DockPanel>
NavigationViewModel
class NavigationViewModel : INotifyPropertyChanged
{
public EmployeeViewModel EmployeeViewModel { get; set; }
public DepartmentViewModel DepartmentViewModel { get; set; }
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set { selectedViewModel = value; OnPropertyChanged("SelectedViewModel"); }
}
public NavigationViewModel()
{
SelectedViewModel = new EmployeeViewModel(OpenEmp);
}
private void OpenEmp(object obj)
{
if (obj.ToString() == "Dept")
{
SelectedViewModel = new DepartmentViewModel();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
EmployeeView
<Grid>
<StackPanel>
<TextBlock Text="This is employee view"/>
<Button Content="Navigate to Dept View" Command="{Binding Navigate}"/>
</StackPanel>
</Grid>
EmployeeViewModel
class EmployeeViewModel
{
private readonly Action<object> navigate;
public ICommand Navigate { get; set; }
public EmployeeViewModel(Action<object> navigate)
{
Navigate = new BaseCommand(OnNavigate);
this.navigate = navigate;
}
private void OnNavigate(object obj)
{
navigate.Invoke("Dept");
}
}

WPF - MVVM Bindings

I have problem with my application, especially with Bindings in WPF MVVM.
I created Model, ViewModel and View, this is part of my code (only this connected with my problem) When I click the button nemed : PointUp i want to see the amount of Team1 points. Can anyone tell me what i'm doing wrong?
View
<Window x:Class="Tabu.Game
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:Tabu"
xmlns:vm="clr-namespace:Tabu.ViewModel"
mc:Ignorable="d"
Title="Game" Height="600" Width="900" Background="Beige">
<Window.DataContext>
<vm:TeamStatistic />
</Window.DataContext>
<Grid>
<Button x:Name="PointUp" Command="{Binding AddPoints }" Content="+"/>
<Label x:Name="PointsTeam1_label" Content="{Binding Team1.TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
</Grid>
Model
'namespace Tabu.Model
{
public class Team
{
public bool IsTeamActive { get; set; }
public int TeamMiss { get; set; }
public int TeamPoints { get; set; }
public int TeamMistake { get; set; }
}
}'
ViewModel
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return TeamPoints; }
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
public ICommand AddPoints
{
get { return new RelayCommand(() => Add_Points()); }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class RelayCommand : ICommand
{
private readonly Func<bool> canExecute;
private readonly Action execute;
public RelayCommand(Action execute)
: this(execute, null) { }
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { if (this.canExecute != null) CommandManager.RequerySuggested += value; }
remove { if (this.canExecute != null) CommandManager.RequerySuggested -= value; }
}
public Boolean CanExecute(object parameter) { return this.canExecute == null ? true : this.canExecute(); }
public void Execute(object parameter) { this.execute(); }
}
}
The problem is here:
public int TeamPoints
{
get { return TeamPoints; } //should be Team1.TeamPoints
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); } //should be Team1.TeamPoints
}
Inside your TeamPoints property in ViewModel you return and set the same property TeamPoints from ViewModel but you should set from Model (Team1). You should return and set Team1.TeamPoints.
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
And Add_Points():
public void Add_Points()
{
Team1.TeamPoints++;
OnPropertyChanged("TeamPoints");
}
You have to update your Binding like this.
<Label x:Name="PointsTeam1_label" Content="{Binding TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
When you bind to Team1.TeamPoints you will not get the Notification from OnPropertyChanged which is inside your TeamPoints property.
I reckon it is because of AddPoints (the command binding). Since this command is binded & you are creating an instance of RelayCommand & returning each time it might be breaking the binding.
A better alternative with CommandBindings are to declare the property and initialize them in the Constructor of the view model.
Ex:
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
private ICommand _AddPoints;
public ICommand AddPoints
{
get { return _AddPoints; }
set { _AddPoints = value; }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public TeamStatistic ()
{
_AddPoinss = new RelayCommand(Add_Points);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}

How to use the CanExecute Method from ICommand on WPF

How does one use the CanExecute Method from the ICommand interface?
In my example i have a SaveCommand which i only what to be enable when the object is saveable. The XAML Code of my Savebutton looks like this:
<Button Content="Save" Command="{Binding SaveCommand, Mode=TwoWay}" />
This is the code of my save class:
class Save : ICommand
{
public MainWindowViewModel viewModel { get; set; }
public Save(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
if (viewModel.IsSaveable == false)
return false;
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
viewModel.Save();
}
}
The save property in the ViewModel looks like this:
public ICommand SaveCommand
{
get
{
saveCommand = new Save(this);
return saveCommand;
}
set
{
saveCommand = value;
}
}
This construct didn't work. The button does not enable its self when isSaveable is true.
Instead of defining your own implementation of ICommand, use a RelayCommand.
In the below sample code, the save Button is enabled when the user types something in the TextBox.
XAML:
<Window x:Class="RelayCommandDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Margin="5" Width="120"/>
<Button Content="Save" Command="{Binding SaveCommand}" Margin="3"/>
</StackPanel>
</Window>
Code behind:
using System;
using System.Windows;
using System.Windows.Input;
namespace RelayCommandDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new VM();
}
}
public class VM
{
public String Name { get; set; }
private ICommand _SaveCommand;
public ICommand SaveCommand
{
get { return _SaveCommand; }
}
public VM()
{
_SaveCommand = new RelayCommand(SaveCommand_Execute, SaveCommand_CanExecute);
}
public void SaveCommand_Execute()
{
MessageBox.Show("Save Called");
}
public bool SaveCommand_CanExecute()
{
if (string.IsNullOrEmpty(Name))
return false;
else
return true;
}
}
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private Action methodToExecute;
private Func<bool> canExecuteEvaluator;
public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
{
this.methodToExecute = methodToExecute;
this.canExecuteEvaluator = canExecuteEvaluator;
}
public RelayCommand(Action methodToExecute)
: this(methodToExecute, null)
{
}
public bool CanExecute(object parameter)
{
if (this.canExecuteEvaluator == null)
{
return true;
}
else
{
bool result = this.canExecuteEvaluator.Invoke();
return result;
}
}
public void Execute(object parameter)
{
this.methodToExecute.Invoke();
}
}
}

c# ListView not updating when Property Changed

My UI is not updating when more data is added to the ObservableCollection. The console output says A first chance exception of type 'System.NullReferenceException' occurred. Should I be using Inotifycollectionchanged instead? Here is some of the code:
<ListView x:Name="ListView2" ItemsSource="{Binding Source={x:Static d:GrabUserConversationModel._Conversation}, UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ListView1_SelectionChanged">
UserConversationModel.cs
public class UserConversationModel : INotifyPropertyChanged
{
public UserConversationModel()
{
}
public string Name
{ get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string Obj)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(Obj));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow
{
static GrabUserConversationModel grabUserConversationModel;
public MainWindow()
{
InitializeComponent();
...
}
static void AddData()
{
grabUserConversationModel.Conversation.Add(new UserConversationModel { Name = "TestName" });
}
GrabUserConversationModel.cs
class GrabUserConversationModel
{
public static ObservableCollection<UserConversationModel> _Conversation = new ObservableCollection<UserConversationModel>();
public ObservableCollection<UserConversationModel> Conversation
{
get { return _Conversation; }
set { _Conversation = value; }
}
...
your property ObservableCollection<UserConversationModel> Conversation is not implementing the INotifyPropertyChanged
public ObservableCollection<UserConversationModel> Conversation
{
get { return _Conversation; }
set { _Conversation = value; OnPropertyChanged("Conversation");}
}

Categories