I tried to implement something earlier this afternoon and have not been able to get it working the way I want.
If I have some XAML like the following (I know it is not complete but it is for illustrative purposes only)...
<Window>
<StackPanel>
<Button />
<UserControl1>
</StackPanel>
</Window>
...and UserControl1 exposes a command property (currently, I am using a RelayCommand for this), how do I bind the Button in the Window to this command. I tried to expose a property in the Window that is bound to the command property in UserControl1 so that I could turn around and re-bind this to the Button but the property in the Window is always null. This pattern seems to work for another property (an integer value). Is there a better way to do this? Is there something with the command that prevents this from occuring?
(1) define your command as a DepenedecyProperty and implement it .
(2) bind the Command property in the button the the MyCommand Property in your UserControl.
public Class UserControl1 : UserControl
{
public UserControl1()
{
MyCommad = new RelayCommand
(
() => { // do some stuff in execute delegate},
() => { return true ;}
);
}
public bool MyCommand
{
get { return (ICommand)GetValue(MyCommandProperty); }
set { SetValue(MyCommandProperty, value); }
}
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register("MyCommand", typeof(ICommand),new FrameworkPropertyMetadata(null));
}
xaml :
<Window>
<StackPanel>
<Button Command={Binding ElementName=control1,Path=MyCommand,Mode=OneWay/>
<UserControl1 x:Name="control1" />
</StackPanel>
</Window>
Related
I Have MainWindow.xaml and MainWindowViewModel, I have User Conterol inside MainWindow.xaml, I want when user clicks User control button to send this event to MainWindowViewModel, I have:
Inside main window I have:
<Controls:UserControl1 CloseBtn="{Binding CloseBtn}" ></Controls:UserControl1>
UserControl1.xaml:
<Button Command="{Binding CloseBtn}" />
UserControl1.cs:
public static readonly DependencyProperty CloseProperty =
DependencyProperty.Register(
"CloseBtn",
typeof(ICommand),
typeof(UserControl1),
new PropertyMetadata(null));
public ICommand CloseBtn
{
get { return (ICommand)GetValue(CloseProperty); }
set { SetValue(CloseProperty, value); }
}
MainWindowViewModel.cs:
public ICommand CloseBtn { get; set; }
public MainWindowViewModel()
{
CloseBtn = new RelayCommand(o => BtnCloseSettings());
}
void BtnCloseSettings()
{
MessageBox.Show("test");
}
The MainWindow and the viewmodel are connected, but this button click doesn't popup the "test" messageBox.
what am I missing?
The problem is this line here:
<Button Command="{Binding CloseBtn}" />
You've create a dependency property in UserControl1, which you are correctly binding with this line:
<Controls:UserControl1 CloseBtn="{Binding CloseBtn}" ></Controls:UserControl1>
But that first binding is binding to the CloseBtn property of the UserControl's DataContext. It needs to bind to the UserControl's CloseBtn dependency property instead. To fix this, start by giving your UserControl a name:
<UserControl x:Class="YourApp.UserControl1"
... etc ...
x:Name="_this">
And then change your button command binding to bind to that instead:
<Button Command="{Binding CloseBtn, ElementName=_this}" />
Or, as mentioned in a comment:
<Button Command="{Binding CloseBtn,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
where you wouldn't need to assign the UserControl's x:Name property, and thus avoid the creation of an otherwise unused private field.
I make my own Control.
Inside that I want to define data template to use it in Custom message box.
In code I open this dialog but can't set start value to check box inside it.
Please help me - how to correctly bind cbVoiceAttChecked variable to CustomMessageBox via DataTemplate named VoiceTemplate
XAML:
<UserControl x:Class="myProj.RDPControl"
...
>
<UserControl.Resources>
<DataTemplate x:Key="VoiceTemplate" >
<StackPanel Margin="32,0,0,0">
<CheckBox x:Name="cbVoiceAtt" Content="..." IsChecked="{Binding cbVoiceAttChecked}"/>
... /*Other checkboxes*/
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
... Here is main control - works perfectly
</Grid>
In code
public partial class RDPControl : UserControl
{
public RDPControl()
{
InitializeComponent();
//this.DataContext = this;
}
public bool cbVoiceAttChecked { get; set; }
....
private void VoiceButton_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
cbVoiceAttChecked = true; // This value binding to temlate!!!
CustomMessageBox messageBox = new CustomMessageBox()
{
Caption = "...",
Message = "...",
ContentTemplate = (DataTemplate)(this.Resources["VoiceTemplate"]), // Use template from xaml
DataContext = this, // I want to use cbVoiceAttChecked variable to bind to dialog
LeftButtonContent = "yes",
RightButtonContent = "no"
};
...
messageBox.Show();
}
You need to either change your cbVoiceAttChecked property into a DependencyProperty, or implement the INotifyPropertyChanged interface in your RDPControl class.
You can find out more about the INotifyPropertyChanged Interface in the INotifyPropertyChanged Interface on MSDN and about DependencyPropertys in the DependencyProperty Class and Dependency Properties Overview pages on MSDN.
Of course, it all depends on what you are doing with the ContentTemplate object inside your RDPControl class. As you did not show that, I cannot confirm that making the above change will fix your problem.
This has bothered me for a while and I'm tired of working around the issue. In WPF, what is the "order of operations" when it comes to:
Setting DataContext
Inheriting DataContext
Evaluating a "hard-coded" property value
Evaluating a {Binding} property value
All this taking into consideration nested controls and templates (when templates are applied).
I've had a number of problematic scenarios, but here's just one example:
Custom user control
<UserControl x:Class="UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel>
<Label Content="{Binding Label1}" />
<Label Content="{Binding Label2}" />
</StackPanel>
</UserControl>
User control code-behind
using System;
using System.Windows;
using System.Windows.Controls;
namespace UserControls
{
public partial class TestUserControl : UserControl
{
public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel1PropertyChanged));
public String Label1
{
get { return (String)GetValue(Label1Property); }
set { SetValue(Label1Property, value); }
}
public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel2PropertyChanged));
public String Label2
{
get { return (String)GetValue(Label2Property); }
set { SetValue(Label2Property, value); }
}
public TestUserControl()
{
DataContext = this;
InitializeComponent();
}
private static void OnLabel1PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
//used for breakpoint
}
private static void OnLabel2PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
//used for breakpoint
}
}
}
Window to use the user control
<Window x:Class="Windows.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControls"
>
<StackPanel>
<Label Content="Non user control label" />
<UC:TestUserControl x:Name="uc" Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
</StackPanel>
</Window>
And the code-behind for the window
using System;
using System.Windows;
namespace Windows
{
public partial class TestWindow : Window
{
public String Label2FromWindow
{
get { return "User control label 2"; }
}
public TestWindow()
{
DataContext = this;
InitializeComponent();
}
}
}
So in this scenario, why doesn't "Label2" in the user control ever get the value from "Label2FromWindow" from the window? I feel like it's a timing issue, where the user control evaluates all of its expressions first, and then the window evaluates its expressions later, and the user control is never "notified" of the window's evaluated values.
The example is hopefully helpful to illustrate one problem, but my real question is:
What is the order of operations with regards to DataContext, Hard-Coded Values on properties, Binding Expressions, Templates, and Nested Controls?
EDIT:
H.B. helped me come to this realization. When the window's DataContext is set to itself, the user control will "inherit" the DataContext. This lets the Binding work on the user control's property, but then within the user control Binding to its local properties won't work. When DataContext is set directly on the user control, the window's Binding to the user control's property no longer works, but the user control can then Bind to its own local properties. Below is the updated code sample that works.
User control:
<UserControl x:Class="UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="uc">
<StackPanel>
<Label Content="{Binding ElementName=uc, Path=Label1}" />
<Label Content="{Binding ElementName=uc, Path=Label2}" />
</StackPanel>
</UserControl>
User control code-behind:
using System;
using System.Windows;
using System.Windows.Controls;
namespace UserControls
{
public partial class TestUserControl : UserControl
{
public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl));
public String Label1
{
get { return (String)GetValue(Label1Property); }
set { SetValue(Label1Property, value); }
}
public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl));
public String Label2
{
get { return (String)GetValue(Label2Property); }
set { SetValue(Label2Property, value); }
}
public TestUserControl()
{
InitializeComponent();
}
}
}
Test window:
<Window x:Class="Windows.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControls"
>
<StackPanel>
<Label Content="Non user control label" />
<UC:TestUserControl Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
</StackPanel>
</Window>
Test window code-behind:
using System;
using System.Windows;
namespace Windows
{
public partial class TestWindow : Window
{
public String Label2FromWindow
{
get { return "User control label 2"; }
}
public TestWindow()
{
DataContext = this;
InitializeComponent();
}
}
}
It's not really about order I think, but rather precedence (maybe I am splitting hairs here). You explicitly set the DataContext of the UserControl -- this means that it will not be inherited, thus your binding looks for the property Label2FromWindow inside the UserControl. Obviously, it does not find it.
Just never set the DataContext of UserControl instances and you should not run into such problems. (Name your UserControl and use ElementName for internal bindings)
For a full precedence list see MSDN.
Another method that works well is to give the first child of your UserControl the x:Name="LayoutRoot". Then in your UserControl constructor, use LayoutRoot.DataContext=this.
This method allows you to set the values of the DependencyProperties defined on the UserControl from the surrounding window, and also still use standard Bindings inside the UserControl markup without using to ElementName or RelativeSource bindings.
Colin Ebererhardt explained this here: http://www.scottlogic.com/blog/2012/02/06/a-simple-pattern-for-creating-re-useable-usercontrols-in-wpf-silverlight.html
I have a Textbox in a User Control i'm trying to update from my main application but when I set the textbox.Text property it doesnt display the new value (even though textbos.Text contains the correct data). I am trying to bind my text box to a property to get around this but I dont know how, here is my code -
MainWindow.xaml.cs
outputPanel.Text = outputText;
OutputPanel.xaml
<TextBox x:Name="textbox"
AcceptsReturn="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Text="{Binding <!--?????--> }"/> <!-- I want to bind this to the Text Propert in OutputPanel.xmal.cs -->
OutputPanel.xaml.cs
namespace Controls
{
public partial class OutputPanel : UserControl
{
private string text;
public TextBox Textbox
{
get {return textbox;}
}
public string Text
{
get { return text; }
set { text = value; }
}
public OutputPanel()
{
InitializeComponent();
Text = "test";
textbox.Text = Text;
}
}
}
You have to set a DataContext in some parent of the TextBox, for example:
<UserControl Name="panel" DataContext="{Binding ElementName=panel}">...
Then the binding will be:
Text="{Binding Text}"
And you shouldn't need this - referring to specific elements from code behind is usually bad practice:
public TextBox Textbox
{
get {return textbox;}
}
I hope this example will help you.
1) Create UserControl.
2) Add to XAML <TextBlock Text="{Binding Path=DataContext.HeaderText}"></TextBlock>
3) In the code behind of that UserControl add
public partial class MyUserControl: UserControl
{
public string HeaderText { set; get; } // Add this line
public MyUserControl()
{
InitializeComponent();
DataContext = this; // And add this line
}
}
4) Outside of the control and let's say in the MainWindow Load event you have to do like
this.gdMain = new MyUserControl{ HeaderText = "YES" };
If your are starting to bind properties I suggest you check some articles on MVVM.
This is a very powerful architecture you can use on WPF. I found it very useful in my projects.
Check this one.
Say I have a very simple UserControl that - for all intents and purposes - is nothing more than TextBox:
public partial class FooBox : UserControl
{
public static readonly DependencyProperty FooTextProperty =
DependencyProperty.Register("FooText", typeof(string), typeof(FooBox));
public FooBox()
{
InitializeComponent();
}
public string FooText
{
get { return textBlock.Text; }
set { textBlock.Text = value; }
}
}
<UserControl x:Class="Namespace.FooBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="textBlock" />
</Grid>
</UserControl>
On the form it's declared as:
<local:FooBox FooText="{Binding Name}" />
The form's DataContext is set to an object that has a Name property. But this is not working for me. What am I missing?
The "get" and "set" parts of a property declaration in a DependencyProperty aren't actually called by the databinding system of WPF - they're there essentially to satisfy the compiler only.
Instead, change your property declaration to look like this:
public string FooText
{
get { return (string)GetValue(FooTextProperty); }
set { SetValue(FooTextProperty, value); }
}
... and your XAML to:
<UserControl ...
x:Name="me">
<Grid>
<TextBlock Text="{Binding FooText,ElementName=me}" />
</Grid>
</UserControl>
Now your TextBox.Text simply binds directly to the "FooText" property, so you can in turn bind the FooText property to "Name" just like you're currently doing.
Another way is to bind TextBlock.Text to a RelativeSource binding that finds the FooText property on the first ancestor of type "FooBox", but I've found that this is more complex than just giving the control an internal x:Name and using element binding.
Turns out the real problem is I was expecting the WPF framework to set my public property whereupon my code would respond to the changes and render according to the new value. Not so. What WPF does is call SetValue() directly and completely circumvents the public property. What I had to do was receive property change notifications using DependencyPropertyDescriptor.AddValueChanged and respond to that. It looks something like (inside the ctor):
var dpd = DependencyPropertyDescriptor
.FromProperty(MyDependencyProperty, typeof(MyClass));
dpd.AddValueChanged(this, (sender, args) =>
{
// Do my updating.
});