I'm trying to hide an element based on a bool. I use a button in this example, but it doesn't work no matter what element type I use.
Here is the XAMl that contains the binding.
<Button
Command="local:CustomCommands.Toggle"
Content="Toggle"
Visibility="{Binding Show, Converter={StaticResource BoolToVis}}" />
Here is the view model I am binding to.
public class MyModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool show = true;
public bool Show
{
get
{
return show;
}
set
{
value = show;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Show)));
}
}
}
}
I've debugged and see the property changing, but nothign updates on the view.
Any ideas?
Related
For exmaple I got 2 TextBlock UI.
the current code below is that both window will get the name
whenever INotifyPropertyChanged is call.
For example I window 2 will get name being updated but
I didn't want window 1 to get updated when INotifyPropertyChanged is call.
Window 1
<TextBlock Text="{binding Name}"/>
Window 2
<TextBlock Text="{binding Name}"/>
View Model
class UserViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string m_Name = "John";
public string Name
{
get { return m_Name; }
set
{
if (value != Name)
{
m_Name = value;
OnPropertyChanged("Name");
}
}
}
}
Add a one-time setting for the binding mode to the one that you don't want to update.
{Binding Name, Mode=OneTime}
You cannot stop a UI control from being updated by the INotifyPropertyChanged interface just at particular times. However, you can simply add another property to bind to your Window 1 and source the value of this from your original property. You can then add a bool property which enables or disables the update of the new property. Try something like this:
public string SecondNameProperty
{
get
{
if (CanUpdate) secondNameProperty = Name;
return secondNameProperty;
}
}
When you want the SecondNameProperty property to update, just ensure that the CanUpdate property is set to true and when you don't want it to be updated, set it to false.
I have a xaml file named MyWindow.xaml, and this xaml has a checkbox declared as..
<CheckBox Name="chkView" IsChecked="{Binding Path=IsChkChecked, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Checked="chkView_Checked" Unchecked="chkView_Checked" />
In MyWindow.xaml.cs,
public partial class MyWindow: UserControl,INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
}
private bool isChkChecked;
public bool IsChkChecked
{
get { return isChkChecked; }
set
{
isChkChecked= value;
OnPropertyChanged("IsChkChecked");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
Now, Iam trying to access this property from another class and change the property, but the checkbox is not getting binded to bool property.
MyLib.MyWindow wnd;
wnd= (MyLib.MyWindow)theTabItem.Content;
wnd.IsChkChecked = true;
Any suggestions would be appreciated.
Your view doesn't bind to IsChkChecked as it doesn't live in the DataContext. Usually you would declare a ViewModel with the property and declare the DataContext to be an instance of this ViewModel. A quick fix would be to change the constructor of the view to set the DataContext to the View itself or change the Binding (as dkozl suggested):
public MyWindow()
{
InitializeComponent();
this.DataContext = this;
}
If you don't specify another binding source by default it will search in DataContext and I cannot see that you set it anywhere. One way is to set RelativeSource against binding to point to Window that publishes IsChkChecked property
<CheckBox Name="chkView" IsChecked="{Binding Path=IsChkChecked, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
I have two windows: the parent and the child. There is the listbox in a parent window.
MainView:
<Button x:Name="btnUpdate" Content="Update"
Command="{Binding Path=MyCommand}" CommandParameter="{Binding ElementName=lstPerson, Path=SelectedItem}" />
<ListBox x:Name="lstPerson" ItemsSource="{Binding Persons}" />
I'm trying to change selected Person two-way update by using ICommand with parameter.
PersonViewModel:
private ICommand myCommand;
public ICommand MyCommand
{
get
{
if (myCommand == null)
{
myCommand = new RelayCommand<object>(CommandExecute, CanCommandExecute);
}
return myCommand;
}
}
private void CommandExecute(object parameter)
{
var ew = new EditWindow()
{
DataContext =
new EditViewModel()
{
Name = ((Person) parameter).Name,
Address = ((Person) parameter).Address
}
};
ew.Show();
}
But selected instance of Person don't changed in listbox. What do I need to write to the xaml or PersonViewModel to make it working?
P.S.
Here is my Person
public class Person : INotifyPropertyChanged
{
private string name;
private string address;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
}
}
public string Address
{
get
{
return address;
}
set
{
address = value;
OnPropertyChanged("Address");
}
}
}
The parameter of your exceution command for the command is wrong. When your binding to SelectedItem of the list which is bound to an ObservableCollection<PersonViewModel>, the selected item will be of type PersonViewModel. Try initializing the ICommand asRelayCommandand modifyCommandExecute(PersonViewModel person)` accordingly.
Secondly, the ICommand is defined on PersonViewModel, but the Command should be on the ViewModel which holds the Persons collection. So, either you move the Command or you define the command on PersonViewModel in a way that it modifies the particular ViewModel, it is on. Than you can spare the CommandParameter, but bind the command like this:
and make CommandExecute something like this:
private void CommandExecute(object parameter)
{
// Modify this, ie. this.Name = something
}
Last thing, your ViewModel needs to implement INotifyPropertyChanged as well and forward the model change notifications. Otherwise changes will not be reflected, unless the binding to an actual property updates it. For example, if you bind like this
<TextBox Text="{Binding Name, Mode=TwoWay}" />
the Name property on the ViewModel will be updated, but if you call
Name = "ChuckNorris"
in your CommandExecute(..) method, the UI won't be updated, because no change notfication is fired.
Is there a way to call methods from the view from the view model? Is this good practice to do so? If not, how would I hide elements in the view from the view model? I'm just a bit confused because I'm used to working with ASP.Net, with code behind, etc.
xaml.cs
btnsave.visibility = visibility.hidden;
btnclose.visibility = visibility.hidden;
For your specific example of hiding elements in the view, you probably want to set up some properties in the ViewModel that define the conditions under which those elements are visible. Then you bind the Visibility property (with a BooleanToVisibilityConverter, most likely) of those elements in the View to those properties in the ViewModel.
More generally, you want to keep the direct coupling between them minimal if you can, but sometimes "reality" gets in the way. I've had some cases where I've passed in the View to the constructor of the ViewModel. Other cases where it's been an interface that the View implements and that gets passed into the ViewModel. So there are options. But you should make sure you HAVE to go that route before doing it.
Example:
XAML:
<Window ...>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="_B2VC" />
</Window.Resources>
<StackPanel>
<Button Content="Save" Visibility="{Binding IsSaveButtonVisible}" />
<Button Content="Close" Visibility="{Binding IsCloseButtonVisible}" />
</StackPanel>
</Window>
ViewModel:
public class ViewModel: INotifyPropertyChanged
{
#region INPC Stuff
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private bool _IsSaveButtonVisible;
public bool IsSaveButtonVisible
{
get { return _IsSaveButtonVisible; }
set
{
if (_IsSaveButtonVisible != value)
{
_IsSaveButtonVisible = value;
RaisePropertyChanged("IsSaveButtonVisible");
}
}
}
private bool _IsCloseButtonVisible;
public bool IsCloseButtonVisible
{
get { return _IsCloseButtonVisible; }
set
{
if (_IsCloseButtonVisible != value)
{
_IsCloseButtonVisible = value;
RaisePropertyChanged("IsCloseButtonVisible");
}
}
}
}
Then your ViewModel changes those properties in response to whatever it needs to (say for instance Save is only valid if they've changed something - once that something is changed, the property on the ViewModel gets updated and bam, that gets propogated to the View.
If you need further examples, i'd just suggest going and reading on MVVM. It takes a bit to grok, but its awesome once in use.
I have simple issue setting a two-way databinding of a checkbox in Silverlight 3.0. It must be a no-brainer but probably I forgot my brain home today...
I defined a Model class to represent my .. 'data'. I implemented the INotifyPropertyChanged interface to enable the UI to see when the data changes.
public class Model : INotifyPropertyChanged
{
private bool _value;
public bool Value
{
get { return this._value; }
set
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Value"));
this._value = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Next I put a checkbox and a button on the .. 'form' :
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="check" IsChecked="{Binding Value, Mode=TwoWay}" Content="SomeLabel"/>
<Button Click="Button_Click" Content="Test" />
</StackPanel>
Then I supplied the data in the constructor :
public MainPage()
{
InitializeComponent();
this.DataContext = new Model() { Value = true };
}
The issue is that you have to click twice on the checkbox for it to check/uncheck unless I de-implement the INotifyPropertyChanged. If de-implement it however, then the UI doesn't notice if I change the underlying data.
If I remove the Mode=TwoWay bit from the IsChecked binding expression then also the UI won't notice the underlying data change even if the Model is implementing the interface.
How can I do to :
Have the checkbox bound to the data at startup
Have the checkbox IsChecked change to modify the underlying data
Have the checkbox detect the underlying data change and update itself?
You've got a sequencing error in your set property procedure, you need to assign to _value before notifying the change :-
set
{
this._value = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}