MVVM-Light Different binding source triggers all ViewModels in context - c#

I'm getting a strange behavior in a test model for mvvm-light:
I created one Window and setted two resources, one grid with two distinct dataContext, the problem is that the two view models are receiving the response even if I'm using only the side of one dataContext. Is there a way to set only the specified data context to fire to the view model that I indicate?
XAML Code:
<Window x:Class="POCWPFValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:POCWPFValidation.ViewModel"
Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
<vm:MainViewModel x:Key="Main"/>
<vm:SecondaryView x:Key="Sec"/>
</Window.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical" DataContext="{Binding Source={StaticResource Main}}">
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox1Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox2Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox3Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox4Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Text="{Binding StringTest, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Button" Command="{Binding Teste}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
<Button Content="Button" Command="{Binding Teste2}" CommandParameter="{Binding ElementName=TextBox1, Path=Text}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
</StackPanel>
<StackPanel Orientation="Vertical" DataContext="{Binding Source={StaticResource Sec}}">
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox1Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox2Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox3Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" IsChecked="{Binding CheckBox4Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Text="{Binding StringTest, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Button" Command="{Binding Teste}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
<Button Content="Button" Command="{Binding Teste2}" CommandParameter="{Binding ElementName=TextBox1, Path=Text}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
The views are the same, so just change the name to SecondaryView
namespace POCWPFValidation.ViewModel
{
public class MainViewModel : ViewModelBase
{
private bool m_blnCheckBox1Checked;
private bool m_blnCheckBox2Checked;
private bool m_blnCheckBox3Checked;
private bool m_blnCheckBox4Checked;
public bool CheckBox1Checked
{
get { return m_blnCheckBox1Checked; }
set
{
Set(ref m_blnCheckBox1Checked, value, true);
}
}
public bool CheckBox2Checked
{
get { return m_blnCheckBox2Checked; }
set
{
Set(ref m_blnCheckBox2Checked, value, true);
}
}
public bool CheckBox3Checked
{
get { return m_blnCheckBox3Checked; }
set
{
Set(ref m_blnCheckBox3Checked, value, true);
}
}
public bool CheckBox4Checked
{
get { return m_blnCheckBox4Checked; }
set
{
Set(ref m_blnCheckBox4Checked, value, true);
}
}
string m_strStringTest = string.Empty;
public string StringTest
{
get { return m_strStringTest; }
set
{
Set(ref m_strStringTest, value, true);
}
}
public RelayCommand<string> Teste2 { get; private set; }
public RelayCommand Teste { get; private set; }
public MainViewModel()
{
Teste = new RelayCommand(MyAction, MyCanExecute);
Teste2 = new RelayCommand<string>(MyAction2, MyCanExecute2);
}
private void MyAction()
{
}
private void MyAction2(string seila)
{
}
private bool MyCanExecute2(string teste)
{
return !string.IsNullOrWhiteSpace(teste);
}
private bool MyCanExecute()
{
if (CheckBox1Checked && CheckBox2Checked && CheckBox3Checked && CheckBox4Checked && StringTest.Equals("teste"))
{
return true;
}
return false;
}
}
}
EDIT:
Sorry, I was not clear with my question, let me try again: like I told before, I have two view models and two distinct datacontext in mainWindow one for each viewmodel. Every time some property on any of these view models changes all the canExecute method of the two viewmodels are triggered. Change some property on view A and the can execute will be triggered on views A and B. Is there a way to only trigger at the specific CanExecute responsible view?

CanExecute is not triggered by the property changes but by CommandManager.RequerySuggested event. Don't worry about when its invoked WPF handles that

Related

Get item of ObservableCollection that triggers button

so I've been working on a smart home implementation in c# for quite a while now but I can't figure out how to inform the Command which executes something, in this case just a remove button as an example, about the item of the Observable that triggers it.
To implement the Collection I'm using a template which also contains a button so that each item of the Collection has a button by it's own.
ObservableCollection with remove Button for each Item
So as you see in there, I have a Remove Button for each Item that is in the ObservableCollection and if I press it I want the Item which contains the Button to be removed but without using something like selectedItem because in that case I need to selected the item first before using the button which is not what I really want because you can press the button without selecting the item/row.
In later time the button will be exchanged for a different function which needs to know which item the button belongs to.
xaml code:
<Page x:Class="Smart_Home.switchPage"
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:Smart_Home"
mc:Ignorable="d"
Title="switchPage" Height="490" Width="998" Background="#10636e" >
<Page.Resources>
<local:SwitchViewmodel x:Key="SwitchViewmodel" />
<DataTemplate x:Key="UserTemplate">
<StackPanel>
<Grid>
<Grid Width="970" Margin="0,0,0,0">
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Width="300">
<TextBlock Text="{Binding Path=schalterName}"/>
</Grid>
<Grid HorizontalAlignment="Center" Width="380">
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Width="200">
<TextBlock Text="{Binding Path=schalterRaum}"/>
</Grid>
<Grid HorizontalAlignment="Right" VerticalAlignment="Center" Width="30">
<TextBlock Text="{Binding Path=schalterNummer}"/>
</Grid>
</Grid>
<Grid HorizontalAlignment="Right" VerticalAlignment="Center" Width="60">
<Button Content="Switch" Height="40" Command="{Binding RemoveSelectedSwitch, Source={StaticResource SwitchViewmodel}}" />
</Grid>
</Grid>
</Grid>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid x:Name="WindowSelection" HorizontalAlignment="Left" Height="490" Margin="0,0,0,0" VerticalAlignment="Top" Width="998">
<Grid Height="400" VerticalAlignment="Top" Grid.ColumnSpan="2">
<Grid x:Name="ListNameGrid" VerticalAlignment="Top" Height="30">
<Grid HorizontalAlignment="Left" Margin="10,0,0,0">
<Label Content="Name" FontSize="14" Foreground="White"/>
</Grid>
<Grid HorizontalAlignment="Center" Width="400">
<Grid HorizontalAlignment="Left">
<Label Content="Room" FontSize="14" Foreground="White"/>
</Grid>
<Grid HorizontalAlignment="Right">
<Label Content="Number" FontSize="14" Foreground="White"/>
</Grid>
</Grid>
<Grid HorizontalAlignment="Right" Margin="0,0,10,0">
<Label Content="Status" FontSize="14" Foreground="White" />
</Grid>
</Grid>
<Grid x:Name="ListGrid" VerticalAlignment="Top" Margin="0,30,0,0">
<ListBox x:Name="Switches_lb" IsSynchronizedWithCurrentItem="true" FontSize="20" Foreground="White" ItemsSource="{Binding SwitchesList, Source={StaticResource SwitchViewmodel}}" ItemTemplate="{StaticResource UserTemplate}" Background="#10636e" BorderThickness="0" Margin="5,0,5,0"/>
</Grid>
</Grid>
</Grid>
</Page>
Viewmodel:
public class SwitchViewmodel
{
public int selectedCollection { get; }
public ObservableCollection<SwitchView> SwitchesList { get; set; }
public ICommand AddNewSwitch { get; set; }
public ICommand RemoveSelectedSwitch { get; set; }
public SwitchViewmodel()
{
AddNewSwitch = new Command(AddNewSwitchExecuteMethod, AddNewSwitchcanexecuteMethod);
RemoveSelectedSwitch = new Command(RemoveSelectedSwitchExeCuteMethod, RemoveSelectedSwitchAddNewSwitchcanexecuteMethod);
SwitchesList = new ObservableCollection<SwitchView>
{
new SwitchView() { schalterName = "Wandlampe", schalterRaum = "Wohnzimmer", schalterNummer = 1, schalterStatus = false },
new SwitchView() { schalterName = "Deckenlampe", schalterRaum = "Küche", schalterNummer = 2, schalterStatus = false },
new SwitchView() { schalterName = "Tischlampe", schalterRaum = "Wohnzimmer", schalterNummer = 39, schalterStatus = false },
};
}
private bool RemoveSelectedSwitchAddNewSwitchcanexecuteMethod(object parameter)
{
return true;
}
private void RemoveSelectedSwitchExeCuteMethod(object parameter)
{
//In here remove method
}
private bool AddNewSwitchcanexecuteMethod(object parameter)
{
return true;
}
private void AddNewSwitchExecuteMethod(object parameter)
{
Console.WriteLine("Command test");
Console.WriteLine("Count vorher: " + SwitchesList.Count());
SwitchesList.Add(new SwitchView() { schalterName = "Wandlampe", schalterRaum = "Wohnzimmer", schalterNummer = 1, schalterStatus = false });
Console.WriteLine("Count nachher: " + SwitchesList.Count());
}
}
Collection:
public class SwitchView
{
public string schalterName { get; set; }
public string schalterRaum { get; set; }
public int schalterNummer { get; set; }
public Boolean schalterStatus { get; set; }
}
Command:
public class Command : ICommand
{
Action<object> executeMethod;
Func<object, bool> canexecuteMethod;
public Command(Action<object> executeMethod, Func<object, bool> canexecuteMethod)
{
this.executeMethod = executeMethod;
this.canexecuteMethod = canexecuteMethod;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
executeMethod(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
So it would be really helpful if someone could help me out with my problem as I'm really new in using MVVM pattern in c# wpf.
Thank you and have a nice day
add CommandParameter.
<Button Content="Switch" Height="40"
Command="{Binding RemoveSelectedSwitch, Source={StaticResource SwitchViewmodel}}"
CommandParameter="{Binding}" />
and use received parameter in command method.
private void RemoveSelectedSwitchExeCuteMethod(object parameter)
{
var item = parameter as SwitchView;
}
since Button is inside ListBox ItemTemplate, CommandParameter="{Binding}" will return DataContext of ListBoxItem - which means corresponding data item

RadioButton IsChecked not binding to separate variables

I have two radio buttons in a group as part of my XAML project:
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Orientation="Horizontal" Grid.Column="0" Margin="20,0,0,0">
<RadioButton x:Name="XMLViewButton" GroupName="DisplayType" IsChecked="{Binding XmlViewIsChecked, FallbackValue=True, Mode=TwoWay}" Content="XML View" Margin="0,0,5,0"/>
<RadioButton x:Name="TextViewButton" GroupName="DisplayType" IsChecked="{Binding TextViewIsChecked, FallbackValue=False, Mode=TwoWay}" Content="Text View" Margin="5,0,0,0"/>
</StackPanel>
And I then have a command later on which refers to these IsChecked bindings:
public void CopyToClipboard(object o)
{
if (TextViewIsSelected == true)
{
Clipboard.SetText(myFile.TextContent);
}
else if (XmlViewIsSelected == true)
{
Clipboard.SetText(myFile.XMLContent);
}
}
However, the XmlViewIsSelected is permanently True and TextViewIsSelected is always false, no matter which radio button is selected. What am I missing?
I think you are mispelling XmlViewIsChecked with XmlViewIsSelected
The following for me is working
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Orientation="Horizontal" Grid.Column="0" Margin="20,0,0,0">
<RadioButton x:Name="XMLViewButton" GroupName="DisplayType" IsChecked="{Binding XmlViewIsChecked, FallbackValue=True, Mode=TwoWay}" Content="XML View" Margin="0,0,5,0"/>
<RadioButton x:Name="TextViewButton" GroupName="DisplayType" IsChecked="{Binding TextViewIsChecked, FallbackValue=False, Mode=TwoWay}" Content="Text View" Margin="5,0,0,0"/>
<Button Content="Check" Click="Button_Click" />
</StackPanel>
public partial class MainWindow : Window
{
public bool XmlViewIsChecked { get; set; }
public bool TextViewIsChecked { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (TextViewIsChecked)
{
Clipboard.SetText("text");
}
else if (XmlViewIsChecked)
{
Clipboard.SetText("xml");
}
}
}

WPF two way mode binding using INotifyPropertyChanged not working

So I am facing a tricky issue. This is my view model:
namespace Market.ViewModel
{
public class BillingViewModel : ViewModelBase
{
#region Private Members
private Customer _customer;
private Product _products;
private string _productId = "asd";
RelayCommand _numClickedCommand;
#endregion
public Customer Customer
{
get { return _customer; }
set
{
_customer = value;
NotifyPropertyChanged("Customer");
}
}
public Product Products
{
get { return _products; }
set
{
_products = value;
NotifyPropertyChanged("Products");
}
}
public bool CanClick
{
get { return true; }
}
public string ProductId
{
get { return _productId; }
set
{
_productId = value;
NotifyPropertyChanged("ProductId");
}
}
public ICommand NumClickedCommand
{
get
{
if (_numClickedCommand == null)
{
_numClickedCommand = new RelayCommand(param => this.NumClicked(param.ToString()),
param => this.CanClick);
}
return _numClickedCommand;
}
}
#region PrivateMethods
private void NumClicked(string numClicked)
{
ProductId = ProductId+numClicked;
}
#endregion
}
}
It inherits ViewModelBase which implements INotifyPropertyCanged.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And my view is:
<Window x:Class="Billing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:Billing"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<viewModel:BillingViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource ViewModel}}">
<controls:NumPad HorizontalAlignment="Left" Margin="265,205,0,-192" VerticalAlignment="Top" Height="307" Width="242"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="247,29,0,0" TextWrapping="Wrap" Text="{Binding ProductId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
</Grid>
</Window>
NumClickedCommand is used in this xaml:
<UserControl x:Class="Billing.NumPad"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
mc:Ignorable="d" Height="109" Width="248">
<UserControl.Resources>
<viewModel:BillingViewModel x:Key="ViewModel"/>
</UserControl.Resources>
<Grid Height="109" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource ViewModel}}">
<Button Content="1" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="1" Command="{Binding NumClickedCommand}"/>
<Button Content="2" HorizontalAlignment="Left" Margin="90,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="2" Command="{Binding NumClickedCommand}"/>
<Button Content="3" HorizontalAlignment="Left" Margin="170,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="3" Command="{Binding NumClickedCommand}"/>
<Button Content="4" HorizontalAlignment="Left" Margin="10,27,0,0" VerticalAlignment="Top" Width="75" CommandParameter="4" Command="{Binding NumClickedCommand}"/>
<Button Content="5" HorizontalAlignment="Left" Margin="90,27,0,0" VerticalAlignment="Top" Width="75" CommandParameter="5" Command="{Binding NumClickedCommand}"/>
<Button Content="6" HorizontalAlignment="Left" Margin="170,27,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="1.034,2.171" CommandParameter="6" Command="{Binding NumClickedCommand}"/>
<Button Content="7" HorizontalAlignment="Left" Margin="10,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="7" Command="{Binding NumClickedCommand}"/>
<Button Content="8" HorizontalAlignment="Left" Margin="90,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="8" Command="{Binding NumClickedCommand}"/>
<Button Content="9" HorizontalAlignment="Left" Margin="170,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="9" Command="{Binding NumClickedCommand}"/>
<Button Content="0" HorizontalAlignment="Left" Margin="10,81,0,0" VerticalAlignment="Top" Width="75" CommandParameter="0" Command="{Binding NumClickedCommand}"/>
<Button Content="Submit" HorizontalAlignment="Left" Margin="90,81,0,0" VerticalAlignment="Top" Width="155" />
</Grid>
</UserControl>
The problem is that updaditing ProductId in the viewmodel doesnt reflect in the view. The initial value of asd is updated at the launch of the application. The controls contain set of buttons that implements ICommand interface and it all calls the NumClicked() in viewmodel. While debugging if i click the button NumClicked() is called then ProductId is updated and NotifyPropertyChanged() is also called but UI does not update, it remains the same. But in case i directly update the UI i.e i enter some value in the textbox the same flow happens, PropertyChanged() is called and after that get is also called to update the value in the viewmodel.
I have gone through many such questions already available but not able to get what exactly is stopping the update of the UI. Any help is appreciated and do ask if anything is missing.
Thank You.
DataContext of Grid and TextBox are bound to a view model instance from Window resources.
NumPad control declares its own instance of view model
NumClickedCommand works with wrong data, not with the displayed object
make sure you have only one instance of view model
NumPad inherits DataContext and shouldn't create a new object and change DataContext
<UserControl x:Class="Billing.NumPad"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
mc:Ignorable="d" Height="109" Width="248">
<Grid Height="109" VerticalAlignment="Top">
<!--all Buttons here-->
</Grid>
you are passing same viewmodel into numpadUser controll and mainWindow also as DataContext, so that will create new instance of viewmodel,so according to me you can use mainwindow's DataContext in NumPad also using Minwindow's GridName, you have to name your grid like
<Grid DataContext="{Binding Source={StaticResource ViewModel}}" x:Name="grdNumPad">
and you can access that DataContext in your NumPad.XAML this way
<Button Content="1" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="1" Command="{Binding DataContext.NumClickedCommand,ElementName=grdNumPad}"/>

WPF - Observablecollection binded DataGrid not updating when i add item from other window

Its my first time with WPF. I already seen many questions but couldn't get the right answer. Scenario is that I have ObservableCollection of order which is implemented by ViewModel. Here is the code
namespace WpfApplication2.ViewModels
{
public class ViewModel : ObservableCollection<Order>
{
static ObservableCollection<Order> orderlist = new ObservableCollection<Order>();
public ParameterCommand ParameterCommand { get; set; }
public ViewModel()
{
this.ParameterCommand = new ParameterCommand(this);
for (int i = 0; i < 10; i++)
{
Order o = new Order();
o.Imei = "Person"+ i;
o.price = i*20;
o.Cust_ID = i;
Add(o);
}
}
public void ParameterMethod(Order order)
{
Order o = new Order();
o.Imei = order.Imei;
o.price = order.price;
o.Cust_ID = order.Cust_ID;
Add(o);
}
}
}
Now I have the Main Window which have the Datagrid binded by above viewmodel
MainWindow.xaml
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view ="clr-namespace:WpfApplication2"
xmlns:model="clr-namespace:WpfApplication2.ViewModels"
Title="MainWindow" Height="359.388" Width="630.791">
<Window.Resources>
<view:Order x:Key="order"></view:Order>
<model:ViewModel x:Key="modelview"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource modelview}}" >
<DataGrid HorizontalAlignment="Left" AutoGenerateColumns="False" Margin="48,26,0,0" DataContext="{Binding Source={StaticResource modelview}}" ItemsSource="{Binding}" VerticalAlignment="Top" Height="235" Width="373">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Imei,Mode=TwoWay}"/>
<DataGridTextColumn Header="Cutomer ID" Binding="{Binding Cust_ID,Mode=TwoWay}"/>
<DataGridTextColumn Header="Price" Binding="{Binding price,Mode=TwoWay}"/>
</DataGrid.Columns>
</DataGrid>
<TextBox HorizontalAlignment="Left" Height="23" DataContext="{Binding Source={StaticResource order}}" Margin="490,69,0,0" Text="{Binding Path=Imei, Mode=TwoWay}" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" TextChanged="TextBox_TextChanged_1"/>
<TextBox HorizontalAlignment="Left" Height="23" DataContext="{Binding Source={StaticResource order}}" Margin="490,119,0,0" Text="{Binding Path=Cust_ID, Mode=TwoWay}" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Height="23" DataContext="{Binding Source={StaticResource order}}" Margin="490,165,0,0" Text="{Binding Path=price, Mode=TwoWay}" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button Content="NEW" HorizontalAlignment="Left" Margin="109,276,0,0" VerticalAlignment="Top" Width="99" Command="{Binding ParameterCommand, Source={StaticResource modelview}}" CommandParameter="{Binding Source={StaticResource order}}" Height="25"/>
<Button Content="NEW" HorizontalAlignment="Left" Margin="239,276,0,0" VerticalAlignment="Top" Width="99" Height="25" Click="Button_Click_1"/>
</Grid>
now when i add the values from main window text boxes to ObservableCollection it is updated in the datagrid but when i use other separate window for adding item in ObservableCollection it got added in it but datagrid is not updated. Can you please help me out
EDIT:
here is the xaml of the window I am adding item to ObservableCollection
Title="New" Height="300" Width="300">
<Window.Resources>
<view:Order x:Key="order"></view:Order>
<model:ViewModel x:Key="modelview"/>
</Window.Resources>
<Grid>
<TextBox HorizontalAlignment="Left" Text="{Binding Path=Imei, Mode=TwoWay}" Height="23" Margin="83,30,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Text="{Binding Path=Cust_ID, Mode=TwoWay}" Height="23" Margin="83,85,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Text="{Binding Path=price, Mode=TwoWay}" Height="23" Margin="83,136,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button Content="Save to grid" HorizontalAlignment="Left" Margin="104,196,0,0" VerticalAlignment="Top" Width="75" Command="{Binding ParameterCommand, Source={StaticResource modelview}}" CommandParameter="{Binding Source={StaticResource order}}"/>
</Grid>
Commands also attaching in case any problem is there
namespace WpfApplication2.ViewModels.Commands
{
public class ParameterCommand : ICommand
{
public ViewModel ViewMod
{
get ;
set ;
}
public ParameterCommand(ViewModel view)
{
this.ViewMod = view;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
this.ViewMod.ParameterMethod(parameter as Order);
}
}
}
ADDED
Main Window.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//ViewModel vm = new ViewModel();
//this.DataContext = vm;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
New win = new New();
win .Owner = this;
win .DataContext = this.DataContext;
win .Show();
}
}
It's cause you are creating new object of ViewModel in new window and using data as DataContext. try below code:
Window w = new Window();
w.DataContext = this.DataContext;
w.Show();
When you open the new window, use current DataContext instance as new window's DataContext. And your code will work fine.
Update
Remove below part from you New Window.
<Window.Resources>
<view:Order x:Key="order"></view:Order>
<model:ViewModel x:Key="modelview"/>
</Window.Resources>
Cause of <model:ViewModel x:Key="modelview"/> a new object of ViewModel is being created with the New Window.
Change your Command as following:
<Button Content="Save to grid" HorizontalAlignment="Left" Margin="104,196,0,0" VerticalAlignment="Top" Width="75" Command="{Binding ParameterCommand}" CommandParameter="{Binding Source={StaticResource order}}"/>
Not sure what are you trying to do in CommandParameter. But your New
Window is getting existing ViewModel object as DataContext.
Command can be directly bound to Button.

WPF enable buttons group

In first column i have list of groups ("First","Second"). In second column i have 5 button's. I want to enable or disable group of button's after choosing their group in first column. How to do this in MVVM pattern?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Data();
}
}
public class Data
{
public List<string> Items { get; set; }
public Data()
{
Items = new List<string>();
Items.Add("First");
Items.Add("Second");
}
}
Xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
</Grid>
Create your VM classes like:
public class Data:INotifyPropertyChanged
{
public ObservableCollection<MyRecord> Items
{
get{
return _items;
}
set{
_items=value;
OnProperyChanged("Items")
}
}
public Data()
{
Items = new ObservableCollection<MyRecord>()
{
new MyRecord(){Title:"First",IsEnable:false}),
new MyRecord(){Title:"Second",IsEnable:false})
};
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyRecord:INotifyPropertyChanged
{
private int _title;
private bool _isEnable;
public int Title
{
get
{
return _title;
}
set
{
_title= value;
OnProperyChanged("Title")
}
}
public bool IsEnable
{
get
{
return _isEnable;
}
set
{
_isEnable= value;
OnProperyChanged("IsEnable")
}
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Now in your Xaml bind the IsEnabled property of each Button to appropriate property...
You can write the following code with BooleanToVisibilityConverter:
//First add BooleanToVisibilityConverter to the window resources
// When you know Items[0] is FIRST use some code like this>>
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Sample:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76"/>
</Grid>
OK, every things is good until this step. Now if you make IsEnable property of each item to TRUE, then the buttons must be Enabled And conversely. To perform it you can:
Write a Command in your Data class and make a binding between each List
item and the command.
Use ListView.SelectionChanged event to make IsEnable property of the Clicked item to TRUE. Note: Now, the type of each item in the ListView is MyRecord.
The best solution to your problem is to use a IValueConverter, in this example I created a convert named GroupToBooleanConverter receiving the value of the selected item in the first column by the parameter value and the button group by parameter 'parameter ', the code converter is below:
public class GroupToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var selectedGroup = value as string;
var buttonGroup = (string)parameter;
return buttonGroup.Equals(selectedGroup);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now in its XAML you must reference the namespace of your turn, in my example the namespace convert is namespaceOfConverter, and must be imported to convert through it, is as follows:
xmlns:converters="clr-namespace:namespaceOfConverter"
Place the attribute up on your Window tag in your XAML. Now you must reference the convert, putting it in the Window resources:
<Window.Resources>
<converters:GroupToBooleanConverter x:Key="GroupToBoolean" />
</Window.Resources>
I called your ListView of lsvGroups:
<ListView ItemsSource="{Binding Items}" x:Name="lsvGroups" Grid.Column="0">
....
Now just use the converter in your buttons, performing binding in the property IsEnabled:
IsEnabled="{Binding SelectedItem, ElementName=lsvGroups,Converter={StaticResource GroupToBoolean},ConverterParameter=First}"
OBs: In the place of First you put the name of group associate with button.

Categories