WPF change value of a child inside UserControl - c#

I need to change a value from MainWindow of a Control inside my CustomControl.
So lets say I want to change the Labels Content inside UserControl MyControl from MainWindow.xaml.
Example:
<UserControl x:Class="XXXXX.MyUserControl"
.
.
.
>
<Grid>
<Label x:Name="TestLabel"/>
</Grid>
</UserControl>
And in MainWindow.xaml:
<MyUserControl x:Name="TestControl" />
Now how can I access Label.Content from Xaml Designer in MainWindow.xaml?
I didn't find anything out there, so hopefully someone knows how to do that.
Thanks a lot

Expose a custom Property in your UserControl, like below
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
var dpd = DependencyPropertyDescriptor.FromProperty(LabelContentProperty, typeof(MyUserControl));
dpd.AddValueChanged(this, (sender, args) =>
{
_label.Content = this.LabelContent;
});
}
public static readonly DependencyProperty LabelContentProperty = DependencyProperty.Register("LabelContent", typeof(string), typeof(MyUserControl));
public string LabelContent
{
get
{
return GetValue(LabelContentProperty) as string;
}
set
{
SetValue(LabelContentProperty, value);
}
}
}
In xaml of MainWindow
<MyUserControl x:Name="TestControl" LabelContent="Some Content"/>

Added the Following to your UserControl
<UserControl x:Class="XXXXX.MyUserControl"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
.
.
>
Have the User Control Implement INotifyPropertyChanged
Add a Property to the user control like this
Private _LabelText As String
Public Property LabelText() As String
Get
Return _LabelText
End Get
Set(ByVal value As String)
_LabelText = value
OnPropertyChanged("LabelText")
End Set
End Property
Update the Label to Bind from that Property
<Label x:Name="TestLabel" Content="{Binding Path=LabelText}"/>
Then in your MainWindow you can change the property accourdingly
<MyUserControl x:Name="TestControl" LabelText="Testing" />
Then your code behind can also reference that property

Related

Binding to property of UserControl doesn't work

I got a custom TextBox which I plan to include in another UserControl, however when setting up the Binding for it, it simply just doesn't bind.
I simplified the code for clarity.
My custom TextBox:
<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
</UserControl>
partial class CustomTextBox : UserControl
{
public string Text
{
get { return (string)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(CustomTextBox),
new PropertyMetadata(String.Empty));
}
This binding works as expected. When using CustomTextBox in another UserControl or Window, I can access the property just as expected.
The following code blocks describe the UserControl that uses CustomTextBox and the corresponding ViewModel with the property I want to bind Text to.
<UserControl>
<UserControl.DataContext>
<vm:MyViewModel />
</UserControl.DataContext>
<local:CustomTextBox Text="{Binding FooBar, UpdateSourceTrigger=PropertyChanged}" />
</UserControl>
public class MyViewModel : INotifyPropertyChanged
{
private string _fooBar;
public string FooBar
{
get { return _fooBar = (_fooBar ?? ""); }
set
{
_fooBar = value; OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
My problem occurs exactly when I want to bind the Text property to a ViewModel in another UserControl, it just doesn't work. In this case I tried to bind the Text property to the FooBar property on the MyViewModel class, however changes to the Text property do not get reflected on the FooBar property and vice-versa. However when I hover over the binding in the XAML view, it shows the type of the property, so I don't exactly see what's wrong here.
My best guess is that it has to do with two bindings accessing the same property.
modify DP registration to include FrameworkPropertyMetadataOptions.BindsTwoWayByDefault option
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(CustomTextBox),
new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

TextBox Binding doesn't work when switching Tab in TabControl

I have a TextBox in a TabControl. If I edit the text in the box and then switch to another tab, the text is lost. If I change focus (via TAB key on keyboard) and then switch to another tab, the new text is set in my viewmodel.
Here is my code:
<Window x:Class="TabSwitchProblem.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">
<TabControl ItemsSource="{Binding Pages}">
<TabControl.ContentTemplate>
<DataTemplate>
<TextBox Text="{Binding PageContent}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
public partial class MainWindow : Window
{
public ObservableCollection<PageViewModel> Pages
{
get { return (ObservableCollection<PageViewModel>)GetValue(PagesProperty); }
set { SetValue(PagesProperty, value); }
}
public static readonly DependencyProperty PagesProperty =
DependencyProperty.Register("Pages", typeof(ObservableCollection<PageViewModel>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
Pages = new ObservableCollection<PageViewModel>();
Pages.Add(new PageViewModel());
Pages.Add(new PageViewModel());
DataContext = this;
}
}
public class PageViewModel : DependencyObject
{
public string PageContent
{
get { return (string)GetValue(PageContentProperty); }
set { SetValue(PageContentProperty, value); }
}
public static readonly DependencyProperty PageContentProperty =
DependencyProperty.Register("PageContent", typeof(string), typeof(PageViewModel), new PropertyMetadata(null));
}
How can I be sure to get the text updated in my viewmodel?
You may need to add UpdateSourceTrigger=LostFocus to the <TextBox Text="{Binding PageContent}" /> line.
Code should look like this
<TextBox Text="{Binding PageContent, UpdateSourceTrigger=LostFocus}" />
That should work.
You should set the UpdateSourceTrigger to PropertyChanged if you want your binding to update the target every time the value changes. By default the UpdateSourceTrigger for Text property of a TextBox is LostFocus, which updates the target only after the focus is lost.
<TextBox Text="{Binding PageContent, UpdateSourceTrigger=PropertyChanged}" />
The previously accepted answer, although it works, involves changing the binding behavior of the textbox to UpdatesourceTrigger=PropertyChanged. This may not be acceptable for some usages of textbox or other input-accepting controls.
A simple fix for this is to manually set focus to another element on your control (or the tabcontrol itself) in code-behind on SelectionChanged of your TabControl. That way the currently focused input element actually loses focus, triggering the binding:
<TabControl x:Name="MyTabControl" SelectionChanged="MyTabControl_OnSelectionChanged">
private void MyTabControl_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
MyTabControl.Focus();
}

How to bind multiple user controls?

I have created the following User Control:
<UserControl x:Class="TextBinder" ...>
<TextBox Text="{Binding ????}" />
</UserControl>
Now I am using my user control twice in my MainWindow. The MainWindow is then bound to my ViewModel (I set the DataContext). Now the problem is: how can I bind my user controls to the user_controlViewModel?
In my ViewModel, I have created two objects let's call them UC_1 and UC_2, they contain different texts and I would like to bind them to their respective user control in my MainWindow.
What should I put at ????
Note: please do not simplify mu TextBox to double textboxes in one usercontrol. This is not what I would like since in my real life example I have more stuff than textbox only and the usercontrol should be used multiple times in one view.
Thanks!
i gave you a general answer:
within a "real(a usercontrol you wanna use with different viewmodels with different property names)" usercontrol you bind just to your own DependencyProperties and you do that with ElementName or RelativeSource binding and you should never set the DataContext within a UserControl.
<UserControl x:Name="myRealUC" x:class="MyUserControl">
<TextBox Text="{Binding ElementName=myRealUC, Path=MyOwnDPIDeclaredInMyUc, Path=TwoWay}"/>
<UserControl>
if you do that you can easily use this Usercontrol in any view like:
<myControls:MyUserControl MyOwnDPIDeclaredInMyUc="{Binding MyPropertyInMyViewmodel}"/>
and for completeness: the Dependency Property
public readonly static DependencyProperty MyOwnDPIDeclaredInMyUcProperty = DependencyProperty.Register(
"MyOwnDPIDeclaredInMyUc", typeof(string), typeof(MyUserControl), new PropertyMetadata(""));
public bool MyOwnDPIDeclaredInMyUc
{
get { return (string)GetValue(MyOwnDPIDeclaredInMyUcProperty); }
set { SetValue(MyOwnDPIDeclaredInMyUcProperty, value); }
}
Thats right, you need yo declare a dependency property in your UserControl:
public partial class TextBinder:UserControl
{
public static readonly DependencyProperty textproperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextBinder));
public string Text
{
get
{
return this.GetValue(textproperty) as string;
}
set
{
this.SetValue(textproperty,value);
}
}
}
And then, you can use your usercontrol in your window at this way:
<YourNamespace:TextBinder Text={Binding ViewModelProperty}/>

WPF checkbox binding

While it is trivial to store a checkbox's checked state in a variable using the checkbox's Click event, how would I do it via databinding? All the examples I have found have the UI updated from some datasource, or bind one control to another; I want to update a member variable when the checkbox is clicked.
TIA for any pointers...
You must make your binding bidirectional :
<checkbox IsChecked="{Binding Path=MyProperty, Mode=TwoWay}"/>
You need a dependency property for this:
public BindingList<User> Users
{
get { return (BindingList<User>)GetValue(UsersProperty); }
set { SetValue(UsersProperty, value); }
}
public static readonly DependencyProperty UsersProperty =
DependencyProperty.Register("Users", typeof(BindingList<User>),
typeof(OptionsDialog));
Once that is done, you bind the checkbox to the dependency property:
<CheckBox x:Name="myCheckBox"
IsChecked="{Binding ElementName=window1, Path=CheckBoxIsChecked}" />
For that to work you have to name your Window or UserControl in its openning tag, and use that name in the ElementName parameter.
With this code, whenever you change the property on the code side, you will change the textbox. Also, whenever you check/uncheck the textbox, the Dependency Property will change too.
EDIT:
An easy way to create a dependency property is typing the snippet propdp, which will give you the general code for Dependency Properties.
All the code:
XAML:
<Window x:Class="StackOverflowTests.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" x:Name="window1" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<CheckBox Margin="10"
x:Name="myCheckBox"
IsChecked="{Binding ElementName=window1, Path=IsCheckBoxChecked}">
Bound CheckBox
</CheckBox>
<Label Content="{Binding ElementName=window1, Path=IsCheckBoxChecked}"
ContentStringFormat="Is checkbox checked? {0}" />
</StackPanel>
</Grid>
</Window>
C#:
using System.Windows;
namespace StackOverflowTests
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public bool IsCheckBoxChecked
{
get { return (bool)GetValue(IsCheckBoxCheckedProperty); }
set { SetValue(IsCheckBoxCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for
//IsCheckBoxChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxCheckedProperty =
DependencyProperty.Register("IsCheckBoxChecked", typeof(bool),
typeof(Window1), new UIPropertyMetadata(false));
public Window1()
{
InitializeComponent();
}
}
}
Notice how the only code behind is the Dependency Property. Both the label and the checkbox are bound to it. If the checkbox changes, the label changes too.
Hello this is my first time posting so please be patient:
my answer was to create a simple property:
public bool Checked { get; set; }
Then to set the data context of the Checkbox (called cb1):
cb1.DataContext = this;
Then to bind the IsChecked proerty of it in the xaml
IsChecked="{Binding Checked}"
The code is like this:
XAML
<CheckBox x:Name="cb1"
HorizontalAlignment="Left"
Margin="439,81,0,0"
VerticalAlignment="Top"
Height="35" Width="96"
IsChecked="{Binding Checked}"/>
Code behind
public partial class MainWindow : Window
{
public bool Checked { get; set; }
public MainWindow()
{
InitializeComponent();
cb1.DataContext = this;
}
private void myyButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Checked.ToString());
}
}
Should be easier than that. Just use:
<Checkbox IsChecked="{Binding Path=myVar, UpdateSourceTrigger=PropertyChanged}" />
if you have the property "MyProperty" on your data-class, then you bind the IsChecked like this.... (the converter is optional, but sometimes you need that)
<Window.Resources>
<local:MyBoolConverter x:Key="MyBoolConverterKey"/>
</Window.Resources>
<checkbox IsChecked="{Binding Path=MyProperty, Converter={StaticResource MyBoolConverterKey}}"/>
This works for me (essential code only included, fill more for your needs):
In XAML a user control is defined:
<UserControl x:Class="Mockup.TestTab" ......>
<!-- a checkbox somewhere within the control -->
<!-- IsChecked is bound to Property C1 of the DataContext -->
<CheckBox Content="CheckBox 1" IsChecked="{Binding C1, Mode=TwoWay}" />
</UserControl>
In code behind for UserControl
public partial class TestTab : UserControl
{
public TestTab()
{
InitializeComponent(); // the standard bit
// then we set the DataContex of TestTab Control to a MyViewModel object
// this MyViewModel object becomes the DataContext for all controls
// within TestTab ... including our CheckBox
DataContext = new MyViewModel(....);
}
}
Somewhere in solution class MyViewModel is defined
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool m_c1 = true;
public bool C1 {
get { return m_c1; }
set {
if (m_c1 != value) {
m_c1 = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("C1"));
}
}
}
}
No backend and ViewModel Code:
I made such check box to control other control's visibility.
<CheckBox x:Name="rulerCheckbox" Content="Is Ruler Visible" IsChecked="True"/>
and in the other control, I added such binding:
Visibility="{Binding IsChecked, ElementName=rulerCheckbox, Mode=TwoWay, Converter={StaticResource BoolVisConverter}}">

Access codebehind variable in XAML

How can I access the public variable which in Sample.xaml.cs file like asp.net <%=VariableName%>?
There are a few ways to do this.
Add your variable as a resource from codebehind:
myWindow.Resources.Add("myResourceKey", myVariable);
Then you can access it from XAML:
<TextBlock Text="{StaticResource myResourceKey}"/>
If you have to add it after the XAML gets parsed, you can use a DynamicResource above instead of StaticResource.
Make the variable a property of something in your XAML. Usually this works through the DataContext:
myWindow.DataContext = myVariable;
or
myWindow.MyProperty = myVariable;
After this, anything in your XAML can access it through a Binding:
<TextBlock Text="{Binding Path=PropertyOfMyVariable}"/>
or
<TextBlock Text="{Binding ElementName=myWindow, Path=MyProperty}"/>
For binding, if DataContext is not in use, you can simply add this to the constructor of the code behind:
this.DataContext = this;
Using this, every property in the code becomes accessible to binding:
<TextBlock Text="{Binding PropertyName}"/>
Another way is to just give a name to the root element of the XAML:
x:Name="root"
Since the XAML is compiled as a partial class of the code-behind, we can access every property by name:
<TextBlock Text="{Binding ElementName="root" Path=PropertyName}"/>
Note: access is only available to properties; not to fields. set; and get; or {Binding Mode = OneWay} are necessary. If OneWay binding is used, the underlying data should implement INotifyPropertyChanged.
For quick-and-dirty Windows in WPF, I prefer binding the DataContext of the Window to the window itself; this can all be done in XAML.
Window1.xaml
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource self}}"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBlock Text="{Binding Path=MyProperty1}" />
<TextBlock Text="{Binding Path=MyProperty2}" />
<Button Content="Set Property Values" Click="Button_Click" />
</StackPanel>
</Window>
Window1.xaml.cs
public partial class Window1 : Window
{
public static readonly DependencyProperty MyProperty2Property =
DependencyProperty.Register("MyProperty2", typeof(string), typeof(Window1), new UIPropertyMetadata(string.Empty));
public static readonly DependencyProperty MyProperty1Property =
DependencyProperty.Register("MyProperty1", typeof(string), typeof(Window1), new UIPropertyMetadata(string.Empty));
public Window1()
{
InitializeComponent();
}
public string MyProperty1
{
get { return (string)GetValue(MyProperty1Property); }
set { SetValue(MyProperty1Property, value); }
}
public string MyProperty2
{
get { return (string)GetValue(MyProperty2Property); }
set { SetValue(MyProperty2Property, value); }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Set MyProperty1 and 2
this.MyProperty1 = "Hello";
this.MyProperty2 = "World";
}
}
In the above example, note the binding used in the DataContext property on the Window, this says "Set your data context to yourself". The two text blocks are bound to MyProperty1 and MyProperty2, the event handler for the button will set these values, which will automatically propagate to the Text property of the two TextBlocks as the properties are Dependency Properties.
It is also worth noting that a 'Binding' can only be set on a DependencyProperty of a DependencyObject. If you want to set a non DependencyProperty (eg. a normal property) on an object in XAML, then you will have to use Robert's first method of using resources in the code behind.
myWindow.xaml
<Window
...
<TextBlock Text="{ Binding Path=testString }" />
</Window>
myWindow.xaml.cs
public partial class myWindow: Window
{
public string testString { get; set; } = "This is a test string";
public myWindow()
{
DataContext = this;
InitializeComponent();
}
}
Important
Set Datacontext
testString MUST be public
testString MUST be a property (have a get and set)

Categories

Resources