How to bind with usercontrol [duplicate] - c#

I created a Dependency Property in the usercontrol, but however changes in the usercontrol was NOT notified to the Viewmodel
Usercontrol
<UserControl x:Class="DPsample.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 x:Name="txtName"></TextBox>
</Grid>
UserControl.cs
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
#region SampleProperty
public static readonly DependencyProperty SamplePropertyProperty
= DependencyProperty.Register("SampleProperty",
typeof(string),
typeof(UserControl1),
new PropertyMetadata(OnSamplePropertyChanged));
public string SampleProperty
{
get { return (string)GetValue(SamplePropertyProperty); }
set { SetValue(SamplePropertyProperty, value); }
}
static void OnSamplePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as UserControl1).OnSamplePropertyChanged(e);
}
private void OnSamplePropertyChanged(DependencyPropertyChangedEventArgs e)
{
string SamplePropertyNewValue = (string)e.NewValue;
txtName.Text = SamplePropertyNewValue;
}
#endregion
}
MainWindow
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DPsample" x:Class="DPsample.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 SampleProperty="{Binding SampleText,Mode=TwoWay}" HorizontalAlignment="Left" Margin="76,89,0,0" VerticalAlignment="Top" Width="99"/>
<Button Content="Show" HorizontalAlignment="Left" Margin="76,125,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
MainWindow.cs
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var item = this.DataContext as MainViewModel;
MessageBox.Show(item.SampleText.ToString());
}
MainViewModel.cs
public class MainViewModel : NotifyViewModelBase
{
public MainViewModel()
{
this.SampleText = "test";
}
private string _sampleText;
public string SampleText
{
get { return _sampleText; }
set { _sampleText = value; OnPropertyChanged("SampleText"); }
}
}

Bind the TextBox.Text property in the UserControl to its SampleProperty like this:
<TextBox Text="{Binding SampleProperty,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
Now you could simply remove your OnSamplePropertyChanged callback.
You might also register SampleProperty to bind two-way by default like this:
public static readonly DependencyProperty
SamplePropertyProperty = DependencyProperty.Register(
"SampleProperty", typeof(string), typeof(UserControl1),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

An alternative way to do this is an ElementName Binding. First assign the x:Name attribute to the UserControl (for example x:Name="MyUC"), then change the binding to:
<TextBox Text="{Binding ElementName=MyUC, Path=SampleProperty}"/>

Related

WPF Data Binding between ViewModel in Window and ViewModel in UserControl

I have a window and an usercontrol used within this window.
And I have done the following:
Bound the window property to window's viewmodel property.
Bound the usercontrol property to usercontrol's viewmodel property.
Bound the usercontrol's property to window's viewmodel property.
In my opinion, I think if I set window property by specific value, usercontrol's viewmodel's property will be set to the same value.
But usercontrol's viewmodel's property was not set to the same value.
Here is whole codes.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window1 w = new Window1();
w.Mode = RegisterMode.Update;
w.Show();
}
}
Window1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100" Mode="{Binding DataContext.Mode, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
Window1.xaml.cs
public partial class Window1 : Window
{
public RegisterMode Mode
{
get { return (RegisterMode)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModeProperty =
DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(Window1), new PropertyMetadata(RegisterMode.None));
public Window1()
{
InitializeComponent();
Binding modeBinding = new Binding();
modeBinding.Source = this.DataContext;
modeBinding.Path = new PropertyPath("Mode");
modeBinding.Mode = BindingMode.TwoWay;
modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
this.SetBinding(Window1.ModeProperty, modeBinding);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show((uc1.DataContext as UCViewModel).Mode.ToString());
}
}
WindowViewModel.cs
public class WindowViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
UserControl1.xaml
<UserControl x:Class="MVVMTest2.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"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
<Grid>
</Grid>
</UserControl>
UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public RegisterMode Mode
{
get { return (RegisterMode)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModeProperty =
DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(UserControl1), new PropertyMetadata(RegisterMode.None));
public UserControl1()
{
InitializeComponent();
Binding modeBinding = new Binding();
modeBinding.Source = this.DataContext;
modeBinding.Path = new PropertyPath("Mode");
modeBinding.Mode = BindingMode.TwoWay;
modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
this.SetBinding(UserControl1.ModeProperty, modeBinding);
}
}
UCViewModel.cs
public class UCViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
What point am I doing wrong?
Please let me know about it.
Try this solution using composition between your ViewModels.
Window1.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300"
Mode={Binding UcViewModel.Mode}> <!-- Added this binding -->
<!-- MOVED THIS TO THE CODE-BEHIND
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
-->
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100"
Mode="{Binding UcViewModel.Mode}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
Window1.xaml.cs
public partial class Window1 : Window
{
public RegisterMode Mode
{
get { return (RegisterMode)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModeProperty =
DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(Window1), new PropertyMetadata(RegisterMode.None));
public Window1()
{
InitializeComponent();
/* THIS IS NOT NEEDED
Binding modeBinding = new Binding();
modeBinding.Source = this.DataContext;
modeBinding.Path = new PropertyPath("Mode");
modeBinding.Mode = BindingMode.TwoWay;
modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
this.SetBinding(Window1.ModeProperty, modeBinding)
*/
// Use the following instead:
this.DataContext = new WindowViewModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show((uc1.DataContext as UCViewModel).Mode.ToString());
}
}
UserControl1.xaml
<UserControl x:Class="MVVMTest2.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"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<!-- THIS PART IS NOT NEEDED
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
-->
<Grid>
</Grid>
</UserControl>
UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public RegisterMode Mode
{
get { return (RegisterMode)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModeProperty =
DependencyProperty.Register("Mode", typeof(RegisterMode), typeof(UserControl1), new PropertyMetadata(RegisterMode.None));
public UserControl1()
{
InitializeComponent();
/* THIS IS NOT NEEDED
Binding modeBinding = new Binding();
modeBinding.Source = this.DataContext;
modeBinding.Path = new PropertyPath("Mode");
modeBinding.Mode = BindingMode.TwoWay;
modeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
this.SetBinding(UserControl1.ModeProperty, modeBinding);
*/
}
}
WindowViewModel.cs
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/* Remove this:
RegisterMode mode = RegisterMode.None;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
*/
// Use composition instead
UCViewModel _ucViewModel = null;
public UCViewModel UcViewModel
{
get
{
if (_ucViewModel == null)
{
_ucViewModel = new UCViewModel();
}
return _ucViewModel;
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And one more thing, you might want to rename the ViewModel property Mode to another name like RegMode. The reason is that it's confusing in the XAML code during binding.
From this:
{Binding Mode, Mode=TwoWay}
Or, this:
{Binding Path=Mode, Mode=TwoWay}
To this less confusing one:
{Binding RegMode, Mode=TwoWay}

One way dependency property changed notification

I'm trying to make a user control with a dependency property. I need to execute certain logic when the dependency property is changed from outside the usercontrol, but that logic shouldn't execute when the dependency property is changed from inside the user control. I have this small sample. I only want to execute certain logic when the value is set from mainwindow and not when it is set by clicking the checkbox. I don't know if PropertyChangedCallbackis the correct way, but this is what I have.
UserControl:
public partial class UserControl1 : UserControl
{
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(UserControl1), new PropertyMetadata(new PropertyChangedCallback(OnPropertyChanged)));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Only process the 5, don't process the 6
}
public UserControl1()
{
InitializeComponent();
}
private void checkBox_Click(object sender, RoutedEventArgs e)
{
MyProperty = 6;
}
}
UserControl xaml:
<UserControl x:Class="WpfApplication4.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>
<CheckBox x:Name="checkBox" Click="checkBox_Click"/>
</Grid>
</UserControl>
MainWindow:
public partial class MainWindow : Window
{
public int MainWindowProperty { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
MainWindowProperty = 5;
}
}
Mainwindow xaml:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 MyProperty="{Binding MainWindowProperty}"/>
</Grid>
</Window>
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!disableProcessing)
{
// Only process the 5, don't process the 6
}
}
bool disableProcessing = false;
private void checkBox_Click(object sender, RoutedEventArgs e)
{
disableProcessing = true;
MyProperty = 6;
disableProcessing = false;
}

WPF UserControl Properties

In the code below, I have a UserControl that contains an ellipse and a textblock. I'd like to create a reusable control that I can bind to that allows me to set the text based on a string, and changes the fill color between Red/Green based on a boolean.
I can do this now by digging deep into the markup and using some complex binding, but I want to reuse this control in a list and it seemed easier to create a control for the purpose. However, I am not sure where to go next and if I should be creating dependency-properties that tie to the values for Fill and Text, or what.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Herp.Derp.View.DeliveryStatusIndicator"
x:Name="UserControl"
d:DesignWidth="91" d:DesignHeight="35">
<Grid x:Name="LayoutRoot">
<StackPanel Orientation="Horizontal">
<Ellipse Width="35" Height="35" Fill="Green">
<Ellipse.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_location_circle}"/>
</Ellipse.OpacityMask>
</Ellipse>
<TextBlock Style="{StaticResource Heading2}"
VerticalAlignment="Center" Margin="3,0,0,0">
<Run Text="FRONT"/>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
here how you can achieve this
UserControl
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty FrontTextProperty = DependencyProperty.Register( "FrontText", typeof(string),typeof(UserControl1), new FrameworkPropertyMetadata(string.Empty));
public string FrontText
{
get { return (string)GetValue(FrontTextProperty); }
set {
SetValue(FrontTextProperty, value);
frontBlock.Text = value;
}
}
public static readonly DependencyProperty EllipseStateProperty = DependencyProperty.Register("EllipseState", typeof(bool), typeof(UserControl1), new FrameworkPropertyMetadata(false));
public bool EllipseState
{
get { return (bool)GetValue(EllipseStateProperty); }
set
{
SetValue(EllipseStateProperty, value);
if (value)
{
ellipse.Fill = new SolidColorBrush( Colors.Green);
}
else
{
ellipse.Fill = new SolidColorBrush(Colors.Red);
}
}
}
}
MainWindow
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 EllipseState="{Binding yourProperty }"/>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="207,94,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>
Yes, to create properties that "parent" XAML can assign bindings to, you need to create aDependencyProperty for each field that you want to bind to.
You would then bind your user control xaml to the backing property for the DP.
Here's what I got for a working solution:
public partial class DeliveryStatusIndicator : UserControl
{
public DeliveryStatusIndicator()
{
InitializeComponent();
}
public static readonly DependencyProperty DeliveryDescriptionProperty = DependencyProperty.Register("DeliveryDescription", typeof(string), typeof(DeliveryStatusIndicator), new FrameworkPropertyMetadata("Default", DescriptionChangedEventHandler));
private static void DescriptionChangedEventHandler(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeliveryStatusIndicator)d).Desc.Text = (string)e.NewValue;
}
public string DeliveryDescription
{
get { return (string)GetValue(DeliveryDescriptionProperty); }
set
{
SetValue(DeliveryDescriptionProperty, value);
}
}
public static readonly DependencyProperty DeliveryStatusProperty = DependencyProperty.Register("DeliveryStatus", typeof(bool), typeof(DeliveryStatusIndicator), new FrameworkPropertyMetadata(false, StatusChangedEventHandler));
private static void StatusChangedEventHandler(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeliveryStatusIndicator)d).Indicator.Fill = (bool)e.NewValue ? new SolidColorBrush(Colors.Green) : new SolidColorBrush(Colors.Red);
}
public bool DeliveryStatus
{
get { return (bool)GetValue(DeliveryStatusProperty); }
set
{
SetValue(DeliveryStatusProperty, value);
}
}
}

Integrating Context-Sensitive help in WPF application following MVVM

I am trying to implement Help functionality for my wpf application which is following the MVVM pattern. I have my help file present, which contains many pages according to the application. Now I need to integrate this into my application.
Here are my requirements:
Pressing F1 opens a certain page in the help file depending on the view model. For this, I guess, I need to bind the F1 command to my view model. How do we bind keys in views?
Pressing F1 on a text field opens help for that text field. I think it will be the same as requirement 1. But the problem here is how will I know that a certain text field, button, or radio button is selected?
Listen for the key in the view (or a base class of the view) and call execute on a HelpCommand on the DataContext.
Pass the control that has focus (or its id, or tag, ...) as an argument to the HelpCommand.
Alternative way to find the focussed control by using the FocusManager
Here is an example:
ContextHelp C#:
public static class ContextHelp
{
public static readonly DependencyProperty KeywordProperty =
DependencyProperty.RegisterAttached(
"Keyword",
typeof(string),
typeof(ContextHelp));
public static void SetKeyword(UIElement target, string value)
{
target.SetValue(KeywordProperty, value);
}
public static string GetKeyword(UIElement target)
{
return (string)target.GetValue(KeywordProperty);
}
}
ViewBase:
public abstract class ViewBase : UserControl
{
public ViewBase()
{
this.KeyUp += ViewBase_KeyUp;
this.GotFocus += ViewBase_GotFocus;
}
void ViewBase_GotFocus(object sender, RoutedEventArgs e)
{
FocusManager.SetIsFocusScope(this, true);
}
void ViewBase_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.F1)
{
var viewModel = this.DataContext as ViewModelBase;
if (viewModel != null)
{
var helpTopic = "Index";
var focusedElement =
FocusManager.GetFocusedElement(this) as FrameworkElement;
if (focusedElement != null)
{
var keyword = ContextHelp.GetKeyword(focusedElement);
if (!String.IsNullOrWhiteSpace(keyword))
{
helpTopic = keyword;
}
}
viewModel.HelpCommand.Execute(helpTopic);
}
}
}
}
ViewModelBase:
public abstract class ViewModelBase: INotifyPropertyChanged
{
public ICommand HelpCommand { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName="")
{
var p = PropertyChanged;
if (p != null)
{
p(this, new PropertyChangedEventArgs(propertyName));
}
}
}
AViewModel:
class AViewModel : ViewModelBase
{
public AViewModel()
{
HelpCommand = new RelayCommand(HelpCommandExecuted, (p)=>true);
}
private void HelpCommandExecuted(object parameter)
{
var topic = parameter as string;
if (!String.IsNullOrWhiteSpace(topic))
{
HelpText = String.Format("Information on the interesting topic: {0}.", topic);
}
}
private string _helpText;
public string HelpText
{
get { return _helpText; }
private set
{
if (_helpText != value)
{
_helpText = value;
OnPropertyChanged();
}
}
}
}
AView C#:
public partial class AView : ViewBase
{
public AView()
{
InitializeComponent();
}
}
AView XAML:
<local:ViewBase x:Class="WpfApplication2.AView"
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:WpfApplication2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label Content="{Binding HelpText}" Margin="10,254,10,0" VerticalAlignment="Top" Height="36"/>
<Button local:ContextHelp.Keyword="Button Info" Content="Button" HorizontalAlignment="Left" Margin="192,32,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox local:ContextHelp.Keyword="TextBox Info" HorizontalAlignment="Left" Height="23" Margin="29,32,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<CheckBox local:ContextHelp.Keyword="CheckBox Info" Content="CheckBox" HorizontalAlignment="Left" Margin="29,80,0,0" VerticalAlignment="Top"/>
<ComboBox local:ContextHelp.Keyword="ComboBox Info" HorizontalAlignment="Left" Margin="138,80,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
</local:ViewBase>
MainWindow XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2" x:Class="WpfApplication2.MainWindow"
Title="MainWindow" Height="700" Width="500">
<Grid x:Name="ViewPlaceholder">
</Grid>
</Window>
MainWindow C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var view = new AView();
var viewModel = new AViewModel();
view.DataContext = viewModel;
ViewPlaceholder.Children.Clear();
ViewPlaceholder.Children.Add(view);
}
}

Why is the Dependency Property not returning its value?

I have a MyUserControl with the following Xaml:
<TextBox Text="{Binding InputValueProperty}" />
In the MyUserControl.xaml.cs I have:
public string InputValue
{
get { return (string)GetValue(InputValueProperty); }
set { SetValue(InputValueProperty, value); }
}
public static readonly DependencyProperty InputValueProperty =
DependencyProperty.Register("InputValueProperty", typeof(string),
typeof(MyUserControl));
In my MainWindow.xaml I create a user control:
<local:MyUserControl InputValue="My Input" />
Later on in my MainWindow.xaml.cs I am trying to access this string. All instances of MyUserControl are contained in a List and I access them with a foreach.
string temp = userControl.InputValue;
This is always null. In my MainWindow.xaml I can see the "My Input" in the text box of the user control but I can't ever seem to get it out of there.
DependencyProperty.Register("InputValueProperty", ...
That should be:
DependencyProperty.Register("InputValue", ...
XAML depends on the registered name of the property, not the name of the property accessor.
It looks like the problem is in your binding. Here's a working example that's modeled off your code with a relative source binding:
Here's the user control:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public string InputValue
{
get { return (string)GetValue(InputValueProperty); }
set { SetValue(InputValueProperty, value); }
}
public static readonly DependencyProperty InputValueProperty =
DependencyProperty.Register("InputValueProperty", typeof(string),
typeof(MyUserControl));
}
<UserControl x:Class="WpfApplication4.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication4" Height="30" Width="300">
<Grid>
<TextBox Text="{Binding Path=InputValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyUserControl}}}" />
</Grid>
</UserControl>
And here's the window:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string text1 = ctrl1.InputValue;
string text2 = ctrl2.InputValue;
string text3 = ctrl3.InputValue;
//breakpoint here
}
}
<Window x:Class="WpfApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication4" Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<local:MyUserControl x:Name="ctrl1" InputValue="My Input" />
<local:MyUserControl x:Name="ctrl2" InputValue="2" />
<local:MyUserControl x:Name="ctrl3" InputValue="3" />
<Button Click="Button_Click" Height="25" Content="debug"/>
</StackPanel>
</Grid>
</Window>
If i throw a breakpoint in the click event i can see the bound values of each of the controls. (if you copy and paste from this be sure to change WpfApplication4 to whatever your project is called.
You need to implement INotifyPropertyChanged on your class that has the property
public class YourClassThatHasTheInputValuePropertyInIt: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public string InputValue
{
get { return (string)GetValue(InputValueProperty); }
set { SetValue(InputValueProperty, value);
NotifyPropertyChanged("InputValue"); }
}
}
This will allow the binding to pick up the property

Categories

Resources