Dependency propery Binding Problem - wpf

Main WINDOW
<Window x:Class="dep2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:dep2"
Title="Window1" Height="300" Width="381">
<Grid>
<local:UserControl1></local:UserControl1>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,77,36" Name="button1" VerticalAlignment="Bottom" Width="75" Click="button1_Click">Button</Button>
</Grid>
</Window>
public partial class Window1 : Window
{
UserControl1 uc = new UserControl1();
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
uc.InfoText = "SAMPLE";
}
}
My User CONTROL
<UserControl x:Class="dep2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="32" Width="300">
<Grid Height="30">
<StackPanel Background="LightCyan">
<TextBox Height="21" Name="textBlock1" Width="120" Text="{Binding Text}" />
</StackPanel>
</Grid>
</UserControl>
public partial class UserControl1 : UserControl
{
public string InfoText
{
get
{
return (string)GetValue(InfoTextProperty);
}
set
{
SetValue(InfoTextProperty, value);
}
}
public static readonly DependencyProperty InfoTextProperty =
DependencyProperty.Register(
"InfoText",
typeof(string),
typeof(UserControl1),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(ChangeText)));
private static void ChangeText(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
(source as UserControl1).UpdateText(e.NewValue.ToString());
}
private void UpdateText(string NewText)
{
textBox1.Text = NewText;
}
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
}
Am getting my value in user control dependency property, but i cant able to bind my value to the text box.am using like this to bind Text="{Binding Text}" is it right,or how to bind my value in user control
i have attached my sample project here,
http://cid-08ec3041618e8ee4.skydrive.live.com/self.aspx/.SharedFavorites/dep2.rar
Can any one look and tell whats wrong in that,
everythng working well, but i cant bind the value in text box,
when u click the button u can see the passed value to usercontrol in message box, but i cant bind that value in text box.
Why????

Your code handles the callback from the dependency property and sets the text box value directly. This is not the role of this callback.
And by setting the Text property, you have lost the binding. Local property setting has a higher priority than bindings. See this blog

Related

Deleting dynamically created button from ListBox in WPF

I'm attempting to delete a dynamically created button from a listbox using the ListBox.Items.Remove, but I keep getting the error of "Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead." Problem is, ItemsControl.ItemsSource is not a valid option in my code.
A little run-down on the code: I have a MainWindow that contains a ListBox and the "Add" and "Delete" buttons. Adding a button sends you to a window where you can input a firstname and lastname. Clicking "Done" adds the newly-created profile's Button to the Listbox (you can access the profile by clicking on said button). I didn't include the Profile code as its empty except for the firstname and lastname being bound to labels there.
How would I access/modify the the button/profile in order to delete them? I know it has to do with the databinding, but I'm thoroughly confused on how to delete the item.
Any help would be much appreciated. I've included the MainWindow and ProfileCreator code below.
<Window x:Class="SavingButtons.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">
<Window.Resources>
<DataTemplate x:Key="UserTemplate">
<StackPanel Orientation="Horizontal">
<Button Name="TestAddButton" Click="TestAddButton_Clicked" Content="{Binding FirstName}" Width="100" Height="40"></Button>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Button Name="AddProfileButton" Content="Add Profile" HorizontalAlignment="Left" Margin="22,29,0,0" VerticalAlignment="Top" Width="75" Click="AddProfileButton_Click"/>
<ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />
<Button Name="DeleteUserButton" Click="DeleteUserButton_Click" Content="Delete User" HorizontalAlignment="Left" Margin="246,69,0,0" VerticalAlignment="Top" Width="105"/>
</Grid>
namespace SavingButtons
{
public partial class MainWindow : Window
{
NewProfile np;
public int buttonNumberID;
public MainWindow()
{
InitializeComponent();
np = new NewProfile(this);
}
private void AddProfileButton_Click(object sender, RoutedEventArgs e)
{
np.Show();
}
//adds button to listbox
internal void TestAddButton_Clicked(object sender, RoutedEventArgs e)
{
Button cmd = (Button)sender;
if (cmd.DataContext is User)
{
//Profile is where the finished information is displayed//
Profile pro = new Profile();
pro.DataContext = cmd.DataContext;
pro.Show();
}
}
//this is where confusion ensues
private void DeleteUserButton_Click(object sender, RoutedEventArgs e)
{
//error occurs here
ButtonHoldersListbox.Items.Remove(ButtonHoldersListbox.SelectedItem);
}
}
}
The Profile Creator:
<Window x:Class="SavingButtons.NewProfile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="NewProfile" Height="300" Width="500">
<Grid>
<Label Content="FirstName" HorizontalAlignment="Left" Margin="64,44,0,0" VerticalAlignment="Top"/>
<Label Content="LastName" HorizontalAlignment="Left" Margin="64,97,0,0" VerticalAlignment="Top"/>
<Button Name="UploadImageButton" Click="UploadImageButton_Click" Content="Upload Image" HorizontalAlignment="Left" Margin="64,146,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox Name="FirstNameTextBox" HorizontalAlignment="Left" Height="23" Margin="126,47,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
<TextBox Name="LastNameTextBox" HorizontalAlignment="Left" Height="23" Margin="126,99,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
<Image Name="imgPhoto" HorizontalAlignment="Left" Height="100" Margin="173,146,0,0" VerticalAlignment="Top" Width="100"/>
<Button Name="ProfileFinishedLaunch" Content="Done" HorizontalAlignment="Left" Margin="360,232,0,0" VerticalAlignment="Top" Width="75" Click="ProfileFinishedLaunch_Click"/>
</Grid>
namespace SavingButtons
{
public partial class NewProfile : Window
{
public ObservableCollection<User> ProfileList;
public MainWindow mMain;
public NewProfile(MainWindow main)
{
InitializeComponent();
ProfileList = new ObservableCollection<User>();
mMain = main;
}
//loads image
private void UploadImageButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog op = new OpenFileDialog();
op.Title = "Select a picture";
op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|" +
"JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
"Portable Network Graphic (*.png)|*.png";
if (op.ShowDialog() == true)
{
imgPhoto.Source = new BitmapImage(new System.Uri(op.FileName));
}
}
//creates a new user out of all the info, inserts new user into the collection, adds new button
private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
{
mMain.buttonNumberID++;
ProfileList.Add(new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source });
mMain.ButtonHoldersListbox.DataContext = ProfileList;
mMain.Show();
this.Hide();
}
You are setting yourListbox` to the others window property and you do it every time after a new item was added.
The error occurs, because the listbox items were set through binding to the ItemsSource property and in this case the ListBox.Items is read only so you can't remove or add item directly.
Instead of what you have now, add an ObservableCollection<User> property to your MainWindow class and bind the ListBox to this property. In the NewProfile window you need to add the new User item to this collection. The delete operation will work with removing the item from that collection (actually the senders DataContext)
public partial class MainWindow : Window
{
public ObservableCollection<User> Profiles {get; set;}
//...
private void DeleteUserButton_Click(object sender, RoutedEventArgs e)
{
var removable = ButtonHoldersListbox.SelectedItem as User;
if(removable != null)
Profiles.Remove(removable);
}
}
<ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Profiles}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />
public partial class NewProfile : Window
{
//creates a new user out of all the info, inserts new user into the collection, adds new button
private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
{
mMain.buttonNumberID++;
var newUser = new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source };
mMain.Profiles.Add(newUser);
//Don't set the listbox.DataContext here
mMain.Show();
this.Hide();
}
if you set itemsource to usercontrol you can't operate it's items directly. Edit it's itemsource instead. give you a simple example.
public partial class MainWindow : Window
{
ObservableCollection<int> ProfileList;
public MainWindow()
{
InitializeComponent();
ProfileList = new ObservableCollection<int>();
this.DataContext = ProfileList;
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Random r = new Random();
int num = r.Next(100);
ProfileList.Add(num);
//lstShow.Items.Add(num); error!
}
private void btnDel_Click(object sender, RoutedEventArgs e)
{
if (lstShow.SelectedIndex > -1)
{
ProfileList.Remove((int)lstShow.SelectedItem);
//lstShow.Items.Remove((int)lstShow.SelectedItem); error!
}
}
}
Thanks to Miklos, I did get my problem solved, however, the binding is still pretty confusing. Mainly: how does the ListBox know to bind the ObservableCollection ProfileList? In Mikalos version, he explicitly binds the ObservableCollection to the Listbox in the XAML(NOTE: Mikalos observable collection is named "Profile")
ItemsSource="{Binding Profiles}"
That would seem the most explicit. Instead, the only way I was only able to make it work was this way(ProfileList is the name I used for the observable collection):
ItemsSource="{Binding}"
Not sure how it knows to bind to my observableCollection. I will include my working code below.
<Window x:Class="SavingButtons.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">
<Window.Resources>
<DataTemplate x:Key="UserTemplate">
<StackPanel Orientation="Horizontal">
<Button Name="TestButton" Click="cmdDeleteUser_Clicked" Content="{Binding FirstName}" Width="100" Height="40"></Button>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Button Name="AddProfileButton" Content="Add Profile" HorizontalAlignment="Left" Margin="22,29,0,0" VerticalAlignment="Top" Width="75" Click="AddProfileButton_Click"/>
<ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />
<Button Name="DeleteUserButton" Click="DeleteUserButton_Click" Content="Delete User" HorizontalAlignment="Left" Margin="246,69,0,0" VerticalAlignment="Top" Width="105"/>
</Grid>
My ProfileCreator Cs:
public partial class NewProfile : Window
{
public MainWindow mMain;
public NewProfile(MainWindow main)
{
InitializeComponent();
mMain = main;
}
//creates a new user out of all the info, inserts new user into the collection, adds new button
private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
{
////Mikalos CODE-----------------------------------------------------------//
var newUser = new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source };
mMain.ProfileList.Add(newUser);
mMain.ButtonHoldersListbox.DataContext = mMain.ProfileList;//Mikalo suggested not putting ListBox.DataContext here,
//however, this is the only place it works.
mMain.Show();
this.Hide();
//---------------------------------------------------------------//
}

DataBinding problems with custom UserControl

I have a strange issue when using DataBinding on a custom UserControl.
My UserControl "UserControl1" has a dependency property LabelText which sets the content of a label within my UserControl1. Furthermore, it has a button that binds the command "MyCommand". This command just shows a message box and is implemented in UserControl1ViewModel.
When I using UserControl1 in my MainWindow with also has its view model (MainWindowViewModel), I would like to set the UserControl's LabelText property in the MainWindow.xaml using a Binding to LabelTextFromMainWindow, but when I do it I have a problem that it uses the wrong DataContext unless you specify it explicitly.
This my code:
public partial class MainWindow : Window
{
private MainWindowViewModel vm;
public MainWindow()
{
InitializeComponent();
DataContext = vm = new MainWindowViewModel();
vm.LabelTextFromMainWindow = "Hallo";
}
}
class MainWindowViewModel : System.ComponentModel.INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this,
new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
#endregion
private string myLabel;
public string LabelTextFromMainWindow
{
get { return myLabel; }
set
{
myLabel = value;
OnPropertyChanged("MyLabel");
}
}
}
/////////
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="224" d:DesignWidth="300">
<Grid>
<Button Command="{Binding MyCommand}" Content="Button" Height="55" HorizontalAlignment="Left" Margin="166,99,0,0" Name="button1" VerticalAlignment="Top" Width="104" />
<Label Margin="30,99,0,0" Name="label1" Height="55" VerticalAlignment="Top" HorizontalAlignment="Left" Width="101" />
</Grid>
</UserControl>
public partial class UserControl1 : UserControl
{
private UserControl1ViewModel vm;
private static UserControl1 instance;
public UserControl1()
{
InitializeComponent();
instance = this;
DataContext = vm = new UserControl1ViewModel();
}
public string LabelText
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(UserControl1), new UIPropertyMetadata(""), OnValidateValueProperty);
private static bool OnValidateValueProperty(object source)
{
if (instance != null)
{
instance.label1.Content = source;
}
return true;
}
}
public class UserControl1ViewModel
{
private DelegateCommand myCommand;
public ICommand MyCommand
{
get
{
if (myCommand == null)
myCommand = new DelegateCommand(new Action<object>(MyExecute),
new Predicate<object>(MyCanExecute));
return myCommand;
}
}
private bool MyCanExecute(object parameter)
{
return true;
}
private void MyExecute(object parameter)
{
MessageBox.Show("Hello World");
}
}
My mainwindow logs as followed:
<Window x:Class="WpfApplication1.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"
xmlns:my="clr-namespace:WpfApplication1">
<Grid>
<my:UserControl1 LabelText="{Binding
Path=DataContext.LabelTextFromMainWindow,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"
HorizontalAlignment="Left"
Margin="114,36,0,0"
x:Name="userControl11"
VerticalAlignment="Top" Height="236" Width="292" />
</Grid>
</Window>
I exspected the following to work correctly.
LabelText="{Binding Path=LabelTextFromMainWindow}"
However, I have to write this one.
LabelText="{Binding Path=DataContext.LabelTextFromMainWindow,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"
What do I have to do in order get the simple Binding to work properly?
By default control inherits DataContext from its parent unless you set it explicitly.
In your case, you explicitly set the DataContext of your UserControl as
DataContext = vm = new UserControl1ViewModel();
which makes all the bindings on your UserControl to look for bindings in class UserControl1ViewModel instead in MainWindowViewModel.
That's why you have to use RelativeSource to get Window's DataContext i.e. you explicitly asked binding to be found in window's DataContext instead in its own DataContext and i see no issue in using RelativeSource.
But, if you want to work like simple binding without RelativeSource, first of all you need to get rid of explicitly setting DataContext and move all commands and properties in MainWindowsViewModel so that your UserControl inherits its DataContext from MainWindow.
OR
You can give name to your window and bind using ElementName -
<Window x:Class="WpfApplication1.MainWindow"
x:Name="MainWindow"> <--- HERE
<Grid>
<my:UserControl1 LabelText="{Binding
Path=DataContext.LabelTextFromMainWindow,
ElementName=MainWindow}"/>

Two way binding use a user control...binding to object, not an element?

I created an object with a simple property with a default value. I then created a user control that has a text box in it. I set the datacontext of the user control to the object.
The text box correctly shows the properties default value but I can't seem to update the property value when the user changes the text box value. I created a simple project to illustrate my code.
Thanks for the help!!
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private string _titleValue;
public string TitleValue
{
get
{
return _titleValue;
}
set
{
_titleValue = value;
textBox1.Text = _titleValue;
}
}
public static readonly DependencyProperty TitleValueProperty = DependencyProperty.Register(
"TitleValue", typeof(string), typeof(UserControl1), new FrameworkPropertyMetadata(new PropertyChangedCallback(titleUpdated))
);
//Don't think I should need to do this!!!
private static void titleUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((UserControl1)d).TitleValue = (string)e.NewValue;
}
}
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="94,97,0,0" Name="textBox1" VerticalAlignment="Top" Width="120"
Text="{Binding Path=TitleValue, Mode=TwoWay}"/>
</Grid>
</UserControl>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dummy = new DummyObject("This is my title.");
userControl11.DataContext = dummy;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("The value is: " + ((DummyObject)userControl11.DataContext).Title);
}
}
<Window x:Class="WpfApplication1.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" xmlns:my="clr-namespace:WpfApplication1">
<Grid>
<my:UserControl1 HorizontalAlignment="Left" Margin="95,44,0,0" x:Name="userControl11" VerticalAlignment="Top" Height="191" Width="293"
TitleValue="{Binding Path=Title, Mode=TwoWay}"/>
<Button Content="Check Value" Height="23" HorizontalAlignment="Left" Margin="20,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
</Window>
The DataContext on your usercontrol isn't set. Specify a Name for it (I usually call mine "ThisControl") and modify the TextBox's binding to Text="{Binding ElementName=ThisControl, Path=TitleValue, Mode=TwoWay}". You can also set the DataContext explicitly, but I believe this is the preferred way.
It seems like the default DataContext should be "this", but by default, it's nothing.
[edit] You may also want to add , UpdateSourceTrigger=PropertyChanged to your binding, as by default TextBoxes' Text binding only updates when focus is lost.

TwoWay Binding With ItemsControl

I'm trying to write a user control that has an ItemsControl, the ItemsTemplate of which contains a TextBox that will allow for TwoWay binding. However, I must be making a mistake somewhere in my code, because the binding only appears to work as if Mode=OneWay. This is a pretty simplified excerpt from my project, but it still contains the problem:
<UserControl x:Class="ItemsControlTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=.}"
x:Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Mode=TwoWay,
UpdateSourceTrigger=LostFocus,
Path=.}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Click="Button_Click"
Content="Click Here To Change Focus From ItemsControl" />
</StackPanel>
</Grid>
</UserControl>
Here's the code behind for the above control:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
namespace ItemsControlTest
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public ObservableCollection<string> MyCollection
{
get { return (ObservableCollection<string>)GetValue(MyCollectionProperty); }
set { SetValue(MyCollectionProperty, value); }
}
// Using a DependencyProperty as the backing store for MyCollection. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCollectionProperty =
DependencyProperty.Register("MyCollection",
typeof(ObservableCollection<string>),
typeof(UserControl1),
new UIPropertyMetadata(new ObservableCollection<string>()));
public UserControl1()
{
for (int i = 0; i < 6; i++)
MyCollection.Add("String " + i.ToString());
InitializeComponent();
myItemsControl.DataContext = this.MyCollection;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Insert a string after the third element of MyCollection
MyCollection.Insert(3, "Inserted Item");
// Display contents of MyCollection in a MessageBox
string str = "";
foreach (string s in MyCollection)
str += s + Environment.NewLine;
MessageBox.Show(str);
}
}
}
And finally, here's the xaml for the main window:
<Window x:Class="ItemsControlTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ItemsControlTest"
Title="Window1" Height="300" Width="300">
<Grid>
<src:UserControl1 />
</Grid>
</Window>
Well, that's everything. I'm not sure why editing the TextBox.Text properties in the window does not seem to update the source property for the binding in the code behind, namely MyCollection. Clicking on the button pretty much causes the problem to stare me in the face;) Please help me understand where I'm going wrong.
Thanx!
Andrew
Ok I believe what is causing this problem is that you are binding directly to a String . Strings are immutable in C# and thus when you change the text, it cannot change the underlying string in the ObservableCollection. What you can do to get around this problem is simply create a model class to hold the string data, and then bind the TextBox.Text to a property inside that class. Here is an example:
public partial class BindingToString : Window
{
public BindingToString()
{
MyCollection = new ObservableCollection<TestItem>();
for (int i = 0; i < 6; i++)
MyCollection.Add(new TestItem("String " + i.ToString()));
InitializeComponent();
myItemsControl.DataContext = this.MyCollection;
}
public ObservableCollection<TestItem> MyCollection
{
get;
set;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Display contents of MyCollection in a MessageBox
string str = "";
foreach (TestItem s in MyCollection)
str += s.Name + Environment.NewLine;
MessageBox.Show(str);
}
}
public class TestItem
{
public string Name
{
get;
set;
}
public TestItem(string name)
{
Name = name;
}
}
Notice that I changed your dependency property to a standard property- there is no reason to make the collection a dependency property. Besides that the only difference is the inclusion of the wrapper class TestItem to hold the string data.
<Window x:Class="TestWpfApplication.BindingToString"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BindingToString " Height="300" Width="300">
<Grid>
<StackPanel>
<ItemsControl ItemsSource="{Binding}"
x:Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Click="Button_Click"
Content="Click Here To Change Focus From ItemsControl" />
</StackPanel>
</Grid>
Now the TextBox is bound to the Name path on TestItem, and this binding works and modifies the collection as expected.

UserControl Property Binding not Working

Given the following code why would "My Stupid Text" never be bound to the UserControls text box?
MainPage.xaml
<Grid x:Name="LayoutRoot">
<Local:Stupid StupidText="My Stupid Text" />
</Grid>
Stupid.xaml
<UserControl x:Class="SilverlightApplication5.Stupid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding StupidText}" />
</Grid>
</UserControl>
Stupid.xaml.cs
public partial class Stupid : UserControl
{
public string StupidText
{
get { return (string)GetValue(StupidTextProperty); }
set { SetValue(StupidTextProperty, value); }
}
// Using a DependencyProperty as the backing store for StupidText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StupidTextProperty =
DependencyProperty.Register("StupidText", typeof(string), typeof(Stupid), new PropertyMetadata(string.Empty));
public Stupid()
{
InitializeComponent();
}
}
Do the following in the constructor of your user control (after InitializeComponent) and your textblock should be aware of its datacontext:
this.DataContext = this;
Give your Stupid control a name:-
<Local:Stupid x:Name="MyStupid" StupidText="My Stupid Text" />
Then you can use element binding like this:-
<TextBlock Text="{Binding StupidText, ElementName=MyStupid}" />

Resources