Binding not working in Checkbox isChecked WPF - wpf

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}}}"/>

Related

WPF DataBinding not updating using BooleanToVisibilityConverter

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?

WPF Custom Control Dependency Property setter not getting called?

I have created a custom control CustomTextBox inherited from TextBox class. I have created a dependency property named CustomTextProperty.
I have binded this DP with my Viewmodel property.
While Registering the DP i have given the property change callback but it is only get called one time when my control gets the binded data initially when my xaml loads.
When i try to set my control from view the binded VM property setter does not gets called and also the propertychangecallback not gets fired.
Please help!!
Code snipet below:
My Custom control
class CustomTextBox : TextBox
{
public static readonly DependencyProperty CustomTextProperty = DependencyProperty.Register("CustomText",
typeof(string), typeof(CustomTextBox),
new FrameworkPropertyMetadata("CustomTextBox",
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnCustomPropertyChange)));
public string CustomText
{
get { return (string)GetValue(CustomTextProperty); }
set { SetValue(CustomTextProperty, value); }
}
private static void OnCustomPropertyChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// This is Demo Application.
// Code to be done Later...
}
}
My View Model:
public class ViewModel : INotifyPropertyChanged
{
private string textForTextBox;
public string TextForCustomTextBox
{
get
{
return this.textForTextBox;
}
set
{
this.textForTextBox = value;
this.OnPropertyChange("TextForCustomTextBox");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChange(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
My Xaml Code with Binding:
<custom:CustomTextBox x:Name="CustomTextBox"
CustomText="{Binding TextForCustomTextBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1" HorizontalAlignment="Center" Width="200" Height="50" />
My Code Behind to set DataContext:
// My View Constructor
public View1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
You said that you declared a CustomText DependencyProperty and data bound it to your view model TextForCustomTextBox property and that much is correct. However, when you said that you tried to set your property from the view, you were mistaken.
What you were actually doing was setting the CustomTextBox .Text property from the view and that wasn't connected to your CustomTextBox.CustomText property. You can connect them like this, although I'm not quite sure what the point of that would be:
<Views:CustomTextBox x:Name="CustomTextBox" Text="{Binding CustomText, RelativeSource={
RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}" CustomText="{Binding
TextForCustomTextBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1" HorizontalAlignment="Center" Width="200" Height="50" />
Try setting your DataContext BEFORE the actual initialization so it is available when the form/control objects are created. If it can't find before, is that what may be causing the failed bindings.

Update binding when nested object changes

I have a some XAML as follows (a simple Label and Button):
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Test="clr-namespace:WpfApplication2">
<StackPanel DataContext="{Binding Path=TestPerson}">
<Label Content="{Binding Path=Name}"></Label>
<Button Content="Button" Click="button1_Click" />
</StackPanel>
</Window>
in the code behind I have:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private Person _person = new Person();
public Person TestPerson { get { return _person; } }
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
_person.Name = "Bill";
//_person = new Person() { Name = "Bill" };
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("TestPerson"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
and the class Person is:
public class Person
{
string _name = "Bob";
public string Name
{
get { return _name; }
set { _name = value; }
}
}
As it is, firing the Propertychanged event does not cause the Label's contents to change to Bill.
I've found I am able to overcome this by either:
Assigning a new object to _person (as in the commented out line)
Removing the DataContext from the StackPanel and have Label bind to Path=TestPerson.Name
I don't understand why I have to actually assign a NEW object to _person for the Label to update, or use the FULL path in the binding.
Is there a way to update the Label without supplying the full path (relying on the DataContext), and without assigning a new object to _person?
You raise PropertyChanged for the Person instance TestPerson. However, TestPerson hasn't changed, it is the Name property of TestPerson that has changed and that is the property the Label is binding to.
Edit: To answer why your first two versions work
Assigning a new object to _person (as in the commented out line)
Here you are actually changing the value of TestPerson and because DataContext is inherited by the children, the Label gets a new DataContext as well so that's why the Binding is updated.
Removing the DataContext from the StackPanel and have Label bind to
Path=TestPerson.Name
This is something I've never seen. The same binding subscribes to PropertyChanged for both TestPerson and Name in Person so raising PropertyChanged for any of these properties will work.
If you want to overcome this without implementing INotifyPropertyChanged for Person, you can change set UpdateSourceTrigger to Explicit
<Label Name="label"
Content="{Binding Path=Name, UpdateSourceTrigger=Explicit}"/>
And update the Binding manually whenever Name changes
private void button1_Click(object sender, RoutedEventArgs e)
{
_person.Name = "Bill";
BindingExpression be = label.GetBindingExpression(Label.ContentProperty);
be.UpdateTarget();
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("TestPerson"));
}
}
Otherwise, just implement INotifyPropertyChanged for Person as well and it will work
public class Person : INotifyPropertyChanged
{
string _name = "Bob";
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You need a little change in your XAML...
In your code behind, instead of setting DataContext as this, set it in XAML via Binding...
<StackPanel DataContext="{Binding RelativeSource={RelativeSource
AncestorType= {x:Type Window},
Mode=FindAncestor},
Path=TestPerson}">
<Label Content="{Binding Path=Name}"></Label>
<Button Content="Button" Click="button1_Click" />
</StackPanel>
Remove the
DataContext = this;
from your code behind.
Let me know if this helps.

How to Databind to a CLR object with Source different to path

I am trying to update a textblock on the view by databinding to a property in the viewmodel (the datacontext for the view).
In the code below; when SelectedItem changes, I want the textblock text to update with the value of the Name property on SelectedItem.
In an attempt to achieve this I have set the binding source to the property that is changing and the binding path to the data I want to update the textblock with.
I.e. I am expecting that the binding engine will see a change on the binding Source (SelectedItem) and pull the data from the binding Path (SelectedItem.Name).
http://msdn.microsoft.com/en-us/library/ms746695.aspx
Setting the SelectedItem raises INPC but the text does not update.
public class ViewModel
{
public IConfiguration Configuration { get; set;}
}
public class Configuration : IConfiguration, INotifyPropertyChanged
{
public Item SelectedItem
{
get { return _item;}
set
{
_item = value;
ItemName = _item.Name;
RaisePropertyChangedEvent("SelectedItem");
}
}
public string ItemName
{
get { return _itemName;}
set
{
_itemName= value;
RaisePropertyChangedEvent("ItemName");
}
}
}
public class Item
{
public string Name { get; set;}
}
I know that changes on Configuration are seen because this works:
<TextBlock Text="{Binding Configuration.ItemName}"/>
But this does not:
<TextBlock Text="{Binding Path=Name, Source=Configuration.SelectedItem}"/>
And nor does this:
<TextBlock Text="{Binding Path=Configuration.SelectedItem.Name, Source=Configuration.SelectedItem}"/>
I'm assuming that this should be straightforward - what have I missed?
I've never actually seen anyone use Binding.Source before, so I don't know much about it. But my guess is that it's not dynamic. When you create your binding, it's grabbing a reference to the object specified in your Source, and then that's it: it uses that same reference for the lifetime of the binding.
Why make this complicated? Just use Path. That's the normal way of doing binding, and it's dynamic all the way -- what you're doing is exactly what Path is intended for.
<TextBlock Text="{Binding Path=Configuration.SelectedItem.Name}"/>
This is probably working, you just can not see it. The Binding engine has not been notified that the Name property of the Item object has changed.
Try implementing the INotifyPropertyChanged interface on the Item class as well (raising the PropertyChanged event as necessary)
This will work for your third binding situation, and also for a similar definition as below
<TextBlock DataContext="{Binding Path=Configuration.SelectedItem}" Text="{Binding Path=Name}"/>
But for a simpler fix, this should work:
<TextBlock Text="{Binding Path=Configuration.SelectedItem.Name}" />
Edit:
public class Configuration : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
private Item _SelectedItem = null;
public Item SelectedItem
{
get
{
return _SelectedItem;
}
set
{
_SelectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
}
public class Item
{
public string Name { get; set; }
}
Then in a Command Execute somewhere I have this:
Configuration.SelectedItem = new Item() { Name = "test" };
Which updates the TextBlock in the View fine:
<TextBlock Text="{Binding Path=Configuration.SelectedItem.Name}" />

WPF- Is there a way to bind to the SelectedValues of both a TreeView and a ListBox?

I need to bind so that the Content of a content control is set to the SelectedValue of either the TreeView or the ListBox. The SelectedValue that was most recently changed should provide the content for the ContentControl.
I was able to get this working using the following concept.
Bind the content control to a read only property "SelectedItem" (with private property _selectedItem).
Bind the ListBox.SelectedItem to a read/write property "SelectedItemLB".
In the SelectedItemLB setter, set the value of _selectedItem, and raise the PropertyChanged event for SelectedItem.
Create a handler for VreeView.SelectedItemChanged, which sets the value of _selectedItem and raises the PropertyChanged event for SelectedItem.
Here is my full code:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.items = new List<object>();
this.items.Add(new Car("Green"));
this.items.Add(new Car("Blue"));
this.items.Add(new Car("Red"));
this._selectedItem = this.items[0];
this.treeView1.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(treeView1_SelectedItemChanged);
this.DataContext = this;
}
void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
this._selectedItem = treeView1.SelectedItem;
PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
}
private List<object> items;
public List<object> Items
{
get { return items; }
set { items = value; }
}
public object SelectedItemLB
{
get { return _selectedItem; }
set
{
_selectedItem = value;
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
}
}
}
private object _selectedItem;
public object SelectedItem
{
get { return _selectedItem; }
}
public event PropertyChangedEventHandler PropertyChanged;
}
The XAML is pretty simple:
<StackPanel>
<ListBox Name="listBox1" ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Path=SelectedItemLB, Mode=TwoWay}" ></ListBox>
<TreeView Name="treeView1" ItemsSource="{Binding Path=Items}">
<TreeView.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"></Setter>
</Style>
</TreeView.Resources>
</TreeView>
<ContentControl Content="{Binding Path=SelectedItem.Color}"></ContentControl>
</StackPanel>
I can't think of a way to do that directly. However there are several straightforward solutions.
A. Use events to set the Content
Simply attach a common handler to the SelectedValueChanged events of your ItemsControls. Whenever one of them changes its selection, the handler will set the Content to whatever was selected. I think this is most simple.
B. Use intermediary properties
Bind the SelectedValue of each ItemsControl to a property. In the property's setter, also set the Content equal to value. This allows you to use data binding instead of event handlers, but it still requires you to write code-behind and it doesn't buy you much. Of course, if you are already binding to properties for other purposes, there is almost no extra cost (only an assignment in each setter) so this method might be preferable.

Resources