I like to create a UserControl with own Header Property.
public partial class SomeClass: UserControl, INotifyPropertyChanged
{
public SomeClass()
{
InitializeComponent();
}
private string header;
public string Header
{
get { return header; }
set
{
header = value;
OnPropertyChanged("Header");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
in UserContol xaml:
Label Name="lbHeader" Grid.Column="0" Content="{Binding Path=Header}"
If I set the value: AA2P.Header = "SomeHeeaderText"; than the label.Caption will not changed. How can I solve that problem?
In Windows xaml:
uc:SomeClass x:Name="AA2P"
If I give directly a value to label (lbHeader.Content = header;) instead of OnPropertyChanged("Header"); its work but, why it does not work with OnPropertyChanged?
I need to use DataContext for somethig else. I try to use dependency property but something is wrong.
public partial class tester : UserControl
{
public tester()
{
InitializeComponent();
}
public string Header
{
get { return (string)GetValue(MyDependencyProperty); }
set { SetValue(MyDependencyProperty, value); }
}
public static readonly DependencyProperty MyDependencyProperty =
DependencyProperty.Register("MyDependencyProperty", typeof(string), typeof(string));
}
<UserControl ... x:Name="mainControl">
<TextBlock Text="{Binding ElementName=mainControl, Path=MyDependencyProperty}"/>
</UserControl>
<Window ...>
<my:tester Header="SomeText" />
</Window>
It does not work. What I do wrong?
Thanks!
The easiest approach is to just the DataContext of your object. One way of doing that is directly in the constructor like this:
public SomeClass()
{
InitializeComponent();
DataContext = this;
}
Setting the DataContext will specify where new data should be fetched from. There are some great tips and information in the article called WPF Basic Data Binding FAQ. Read it to better understand what the DataContex can be used for. It is an essential component in WPF/C#.
Update due to update of the question.
To my understanding you should change the first argument of DependencyProperty.Register to the name of the property that you want to bind to, here "Header" as well as the second argument to the type of your class, here SomeClass. That would leave you with:
public static readonly DependencyProperty MyDependencyProperty =
DependencyProperty.Register("Header", typeof(SomeClass), typeof(string));
But i seldom use dependency properties so I am not positive that this is it, but its worth a try..
If you need the Data context for something else. You can also utilize the ElementName property in the Binding.
<UserControl
x:Class="MyControl.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="mainControl">
<TextBlock Text="Binding ElementName=mainControl, Path=MyDependencyProperty}"/>
</UserControl>
[Edit]
I should add something. Make the "Header" property a dependency property, this will make your live much easier. In UI Controls you should make property almost always a dependency property, every designer or user of your control will thank you.
The UserControl itself needs the DataContext of where it is used later. But the controls inside the UserControl need the UserControl as their DataContext, otherwise they also will inherit the DataContext from the later usage context. The trick is to set the DataContext of the UserControl's child to that of the UserControl, so it now can use the dependency properties of the UserControl.
<UserControl x:Class="MyControl.MyUserControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl,AncestorLevel=1}}">...</Grid>
</UserControl>
If you do this this way the children of the Grid can have simple {Binding dp's name} without additionally ElementName parameters.
Related
I created UserControl with viewmodel. It has DependencyProperty which only works if the value is passed directly. If the value is passed through the binding, it no longer works.
Here is the view code:
This is a closed element not associated with any other. All listed items belong to him. This is a code shortening, I am not going to present whole, immeasurable structures.
View
public partial class SomeView : UserControl
{
public SomeView()
{
InitializeComponent();
SetBinding(ActiveProperty, new Binding(nameof(SomeViewModel.Active)) { Mode = BindingMode.OneWayToSource });
}
#region ActiveProperty
public static readonly DependencyProperty ActiveProperty = DependencyProperty.Register(nameof(Active), typeof(bool), typeof(VNCBoxView));
public bool Active
{
get { return (bool)GetValue(ActiveProperty); }
set { SetValue(ActiveProperty, value); }
}
}
VievModel
public class SomeViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool active;
public bool Active
{
get { return active; }
set
{
active = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Active)));
}
}
}
UserControl
<UserControl ...>
<UserControl.DataContext>
<viewModels:SomeViewModel />
</UserControl.DataContext>
<Grid>
<TextBlock Text="{Binding Active}" />
</Grid>
</UserControl>
===================================================
When working with a ready component, which is an individual, separate entity, the problem occurs depending on how it is used.
I remind you that the elements used in the view in question are a closed whole that does not connect with the element in which it is used. It is the transfer of value that is the matter of the problem.
This is working usage:
<local:SomeView Active="True" />
In viewmodel, the setter is invoked twice, once with false and then with true.
If the value comes from binding, it doesn't work:
<local:SomeView Active="{Binding SomeParentProperty}" />
In viewmodel, setter is only called once with the value false.
Setters in a view are never called, in both cases.
Please help
There is no IsConnected property in the SomeViewModel instance in the current DataContext of the UserControl, hence the Binding
<local:SomeView Active="{Binding IsConnected}" />
won't work. It tries to resolve the PropertyPath against the current DataContext, unless you explicitly specify its Source, RelativeSource or ElementName.
This is the exact reason why UserControls should never explicitly set their own DataContext, and hence never have something like an own, private view model.
The elements in the UserControl's XAML would not bind to properties of such a private view model object, but directly to the properties of the UserControl, for example like
<TextBlock Text="{Binding Active,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
When you set the DataContext explicitly in the UserControl like this:
<UserControl.DataContext>
<viewModels:SomeViewModel />
</UserControl.DataContext>
...you can no longer bind to SomeView's DataContext in the consuming view like this:
<local:SomeView Active="{Binding IsConnected}" />
...because SomeViewModel doesn't have any IsConnected property.
You should avoid setting the DataContext explicitly and let the UserControl inherit its DataContext from its parent element. You can still bind to the dependency property of the UserControl itself using a RelativeSource or an ElementName:
<UserControl ...>
<Grid>
<TextBlock Text="{Binding Active, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Grid>
</UserControl>
Besides, SomeViewModel seems superfluous in your example since the UserControl already has an Active property.
Does anybody know how I can synchronize my properties, which are in a ViewModel, with my Dependency Properties, which are in the View?
I am trying to make a UserControl, which will then be hosted by a WPF-Window (MainWindow.xaml). The UserControl has an own ViewModel which contains ICommands and properties.
The problem is, that I also have to return certain properties to the MainWindow(.xaml) and also set them.
Currently my classes are looking like that:
MainWindow.xaml
<TextBox Name="tbInput" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Row="0"></TextBox>
<local:View x:Name="appEntryView" Pfad="{Binding ElementName=tbInput, Path=Text}" Grid.Row="1" Margin="10"/>
View.xaml
<UserControl x:Class="DependencyProperties.Test"
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:local="clr-namespace:DependencyProperties_Intro"
x:Name="obj"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding ElementName=obj, Path=Pfad}"/>
</Grid>
View.xaml.cs
public partial class View: UserControl, INotifyPropertyChanged
{
public String Pfad
{
get { return (String)GetValue(PfadProperty); }
set { SetValue(PfadProperty, value); OnNotifyPropertyChanged("Pfad"); }
}
// Using a DependencyProperty as the backing store for Path. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PfadProperty =
DependencyProperty.Register("Pfad", typeof(String), typeof(GraphSharpTest), new PropertyMetadata(default(string)));
public View()
{
InitializeComponent();
this.DataContext = new ViewModel();
var name = "Pfad";
var binding = new Binding(name) { Mode = BindingMode.TwoWay };
this.SetBinding(PfadProperty, binding);
}
}
ViewModel.cs
public class ViewModel: INotifyPropertyChanged
{
private String m_Pfad;
public String Pfad
{
get { return m_Pfad; }
set { m_Pfad = value; OnNotifyPropertyChanged("Pfad"); }
}
public void OnNotifyPropertyChanged(String info)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info));
}
public event PropertyChangedEventHandler PropertyChanged;
}
The dependency property works fine, but the setter method of "Pfad" in the ViewModel never gets called at all.
Thanks in advance!
Raising PropertyChanged in the CLR properties of dependency properties is a common mistake. You should not place any code there as it is not used by bindings at all. They exist merely for setting the property once in code or XAML, thus you also will not hit any breakpoints you set there.
var name = "Pfad";
var binding = new Binding(name) { Mode = BindingMode.TwoWay };
this.SetBinding(PfadProperty, binding);
I take it you want to forward the value to your view-model. This is not going to work as you can only bind the property once. Right now you also bind the property here:
<local:View x:Name="appEntryView" Pfad="{Binding ElementName=tbInput, Path=Text}" Grid.Row="1" Margin="10"/>
You could subscribe to the dependency property changes using the respective meta data when registering it, providing a callback, there you could set the value in the view-model.
The thing is: The view-model is private to the View, there really is no point in doing this synchronization if no-one has access to the data. You probably want the property to be either settable from the outside, treating the UserControl more like a control, discarding the view-model, or you want the view-model to be passed from outside as DataContext, and the view binds directly to it.
You need to be careful with explicitly setting the DataContext of UserControls in their definition, as it can obfuscate what is happening and lead to bindings unexpectedly breaking. If you want to set properties on the UserControl instance i would recommend avoiding it.
I'm currently developping an universal app in C#/XAML with MVVM (not MVVM Light) and I have trouble for the XAML part.
I'd like to display one or another StackPanel when a dependency property changed in my ViewModel. I think the code speaks for itself.
<StackPanel Visibility="{Binding MyProperty, Converter={StaticResource BooleanToVisibilityConverter}}">
<!-- Some content -->
</StackPanel>
<StackPanel Visibility="{Binding MyProperty, Converter={StaticResource InvertBooleanToVisibilityConverter}}">
<!-- Some another content -->
</StackPanel>
And here is the definition of the dependency property.
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
"MyProperty",
typeof (bool),
typeof (MyViewModel),
new PropertyMetadata(true));
public bool MyProperty
{
get { return (bool) GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); OnPropertyChanged(); // Implemented by ReSharper }
}
I guess you figure it out that MyProperty is a boolean that I convert into a Visibility via the converters. So, when MyProperty changed in the ViewModel, the view isn't updated.
I already tried to use the UpdateSourceTrigger property but it's not working. Also, I have no binding error and converters are working fine (I only see one StackPanel at the app launch).
Please keep in mind that I don't want to use the code behind part unless there is no other solution.
Thanks for your help.
I finaly gave up and used the code behind part and it's working fine now.
Are your <StackPanel>s part of some UserControl? If not, why are you using DependencyProperty?
Your implementation is quite off as well.
Lets assume for a minute that this is not part of a Custom Control (correct me -- if I'm wrong, I will rewrite the solution)
So you have a ViewModel and you want to hook up some Properties to it. You really don't need to implement DependencyProperty to do what you want to do, but I will entertain you by implementing it your way.
This is a sample ViewModel with 1 (one) property
using Windows.UI.Xaml;
using System.ComponentModel;
// very simple view model
class MyViewModel : DependencyObject, INotifyPropertyChanged
{
// implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// register
public static DependencyProperty FooterTitleProperty = DependencyProperty.Register("FooterTitle", typeof(string), typeof(MyViewModel),
new PropertyMetadata(string.Empty, OnFooterTitlePropertyChanged));
// the actual property
public string FooterTitle
{
get { return (string) GetValue(FooterTitleProperty); }
set
{
SetValue(FooterTitleProperty, value);
}
}
// this will fire when the property gets change
// it will call the OnPropertyChanged to notify the UI element to update its layout
private static void OnFooterTitlePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
MyViewModel mvm = dependencyObject as MyViewModel;
mvm.OnPropertyChanged("FooterTitle");
}
}
To test out the code we will make a very simple XAML form
<Grid x:Name="ContentPanel">
<StackPanel>
<TextBlock x:Name="tb" Text="{Binding FooterTitle}" FontSize="48"></TextBlock>
<Button Content="Test Property" Click="Button_Click_1"></Button>
</StackPanel>
</Grid>
When you click on the button we will change the Textbox's Text
public sealed partial class MainPage : Page
{
// create the view model
MyViewModel vm = new MyViewModel();
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
// set the text we initial want to display
vm.FooterTitle = "default text";
// set the DataContext of the textbox to the ViewModel
tb.DataContext = vm;
}
// after the button is click we change the TextBox's Text
private void Button_Click_1(object sender, RoutedEventArgs e)
{
// change the text
vm.FooterTitle = "Test Property Has Changed.";
// what happens is the Setter of the Property is called first
// after that happens it launches the `OnFooterTitlePropertyChanged` event
// that we hook up with the Register function.
// `OnFooterTitlePropertyChanged` launches the INotifyPropertyChanged event
// then finally the TextBox will updates it's layout
}
}
At this point you can guess you really don't need the DependencyProperty and say why can't I just launch the INotifyPropertyChanged in the Setter instead? Well you can and it is probably the prefer method.
If all these is part of a UserControl then I can see using a DependencyProperty then in the OnFooterTitlePropertyChanged event you can set the
name_of_textbox.Text = FooterTitle;
I think property name should be given with OnPropertyChanged method, like this;
public bool MyProperty
{
get { return (bool) GetValue(MyPropertyProperty); }
set {
SetValue(MyPropertyProperty, value);
OnPropertyChanged("MyProperty");
}
}
https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.data.inotifypropertychanged.propertychanged
I'm trying to learn how to use WPF binding and the MVVM architecture. I'm running into some trouble with Dependency Properties. I've tried to control the visibility of an item on the view by binding it to a DependencyProperty in the DataContext, but it doesn't work. No matter what I set the GridVisible value to in the constructor of the view model below, it is always displayed as visible when I run the code.
Can anyone see where I'm going wrong?
C# code (ViewModel):
public class MyViewModel : DependencyObject
{
public MyViewModel ()
{
GridVisible = false;
}
public static readonly DependencyProperty GridVisibleProperty =
DependencyProperty.Register(
"GridVisible",
typeof(bool),
typeof(MyViewModel),
new PropertyMetadata(false,
new PropertyChangedCallback(GridVisibleChangedCallback)));
public bool GridVisible
{
get { return (bool)GetValue(GridVisibleProperty); }
set { SetValue(GridVisibleProperty, value); }
}
protected static void GridVisibleChangedCallback(
DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
// Do other stuff in response to the data change.
}
}
XAML code (View):
<UserControl ... >
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</UserControl.Resources>
<UserControl.DataContext>
<local:MyViewModel x:Name="myViewModel" />
</UserControl.DataContext>
<Grid x:Name="_myGrid"
Visibility="{Binding Path=GridVisible,
ElementName=myViewModel,
Converter={StaticResource BoolToVisConverter}}">
<!-- Other elements in here -->
</Grid>
</UserControl>
I've looked at several tutorials online, and it seems like I'm correctly following what I've found there. Any ideas? Thanks!
Take the ElementName off your binding, that doesn't seem correct.
Change it to:
<Grid x:Name="_myGrid"
Visibility="{Binding Path=GridVisible,
Converter={StaticResource BoolToVisConverter}}">
Have your ViewModel implement INotifyPropertyChanged rather than inheriting from DependencyObject.
Implement the interface and raise PropertyChanged from your setter for the property.
private bool gridVisible;
public bool GridVisible
{
get { return gridVisible; }
set
{
gridVisible = value;
OnPropertyChanged("GridVisible");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The point of setting the ViewModel as DataContext is to enable easy relative bindings, all bindings where you only specify the Path take the DataContext as source which is inherited throughout the UserControl (unless it is set otherwise, for example in the templated items of an ItemsControl)
So once the DataContext is set on the UserControl you normally do not specify any source when binding to the VM. (Sources are ElementName, RelativeSource and Source)
Further i personally would not make ViewModels inherit from DependencyObject since this introduces thread-affinity, also the point of DependencyProperties is making sparse data structures more efficient by not creating unnecessary fields in all of them (ViewModels normally are quite the opposite of sparse).
I've stumbled over the following problem. I've got a checkbox whose IsChecked property is bound to a CLR property in my MainWindow class. Here's the source code.
Code behind (MainWindow.xaml.cs):
namespace MenuItemBindingTest {
public partial class MainWindow : Window, INotifyPropertyChanged {
private bool m_backedVariable = false;
public bool IsPressAndHoldEnabled {
get { return this.m_backedVariable; }
set {
this.m_backedVariable = value;
OnPropertyChanged("IsPressAndHoldEnabled");
MessageBox.Show("Item changed: " + this.m_backedVariable);
}
}
public MainWindow() {
InitializeComponent();
this.m_checkbox.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
if (this.PropertyChanged != null) {
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
XAML code (MainWindow.xaml):
<Window x:Class="MenuItemBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Binding Problem Test" Width="525" Height="350">
<DockPanel>
<CheckBox x:Name="m_checkbox"
IsChecked="{Binding IsPressAndHoldEnabled}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="Is Press and Hold enabled"/>
</DockPanel>
</Window>
The problem now is that the set accessor for the property IsPressAndHoldEnabled is never called (ie. the message box never shows) when the user checks or unchecks the check box. It does, however, work when I rename the property to something else - like IsPressAndHoldEnabled2.
My question now is: Why can't I use IsPressAndHoldEnabled as name for my property? Does this have anything to do with the property Stylus.IsPressAndHoldEnabled existing?
Interesting. I don't have answers why, but I have workarounds:
Seperating the IsPressAndHoldEnabled property out to a seperate ViewModel class worked, unless the class was derived from FrameworkElement.
Also, changing from a regular property to a Dependency Property in the same MainWindow class worked -- the DP changed callback fires.
Have you specified TwoWay as your binding mode? Although I think CheckBox.IsChecked defaults to TwoWay binding mode...
I think you may have messed up your binding context, so that it is not finding the IsPressAndHoldEnabled property. Bindings in WPF fail silently -- a royal pain if you ask me.
Check that the check-box is really bound to that property, and that the binding context really is your MainWindodw class object.