Get hard coded param from WPF UserControl to code behind - c#

I 'm trying to do something really simple: I have a UserControl, where I want to pass a simple string parameter.
WPF MessagePage.xaml
<Page
x:Class="MuchroomPhone.MessagePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
//...
<PivotItem Header="Nouveaux">
<local:MessageUC MessType="new"/>
</PivotItem>
<PivotItem Header="Lus" >
<local:MessageUC MessType="read"/>
</PivotItem>
<PivotItem Header="Envoyés" >
<local:MessageUC MessType="send"/>
</PivotItem>
<PivotItem Header="Tous" >
<local:MessageUC MessType="all"/>
</PivotItem>
//...
I want to get the MessType from the code behind of the MessageUC.
eg. : I want to get the string "new" in the MessageUC.xaml.cs
I've tried that so far:
MessageUC.xaml
<UserControl
x:Class="MuchroomPhone.MessageUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MuchroomPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
//I don't think the content of the UC is important for my issue, but if you wanted to I can give it too.
MessageUC.xaml.cs
public sealed partial class MessageUC : UserControl
{
public string _messType;
public string MessType
{
get{ return _messType;}
set{this._messType = value;}
}
public ObservableCollection<Message> listMessages { get; set; }
public MessageUC()
{
this.InitializeComponent();
Debug.WriteLine(MessType);
this.fetchUserData();
}
But the MessType string is empty...
Any ideas how to achieve that?
PS: I think there should be a way less verbose way for do that, so if you know a "simple" trick, would be great!
Thanks
EDIT: So If I use a simple property, it's should work? Cause I still have null on MessType...
I've also tried with a Dependency Property, and MessType is an empty string.
EDIT 2: I think I understand what is wrong. Actually MessType doesn't exist on MessageUC.xaml. So the code behind can't find it. Perhaps isn it possible to just pass variable to my Page MessagePage.xaml directly to the User Control MessageUC?

all you need is move fetchUserData to loaded event:
public sealed partial class MessageUC : UserControl
{
public string MessType { get; set; }
public MessageUC()
{
InitializeComponent();
Debug.Writeline(MessType); //null
Loaded += MessageUC_Loaded;
}
public void MessageUC_Loaded(object sender, EventArgs e)
{
Debug.Writeline(MessType); //new
this.fetchUserData();
}
}
DependencyProperty is not needed! Your original code doesn't work, because ctor in invoked before the property is set. DependecyProperty does not solve this, but enables databinding, styling, animating of the property.

You only need a DependencyProperty if you want to data bind to it. In your case you can just use a normal property.

This is a set of instructions that should work. However you didn't show the definition of your control so the code below may need some modifications and adjustments.
So start with registering a dependency property:
public static readonly DependencyProperty _messTypeProperty =
DependencyProperty.Register("_messType", typeof(String),
typeof(MessageUC), new FrameworkPropertyMetadata(string.Empty));
public String _messType
{
get { return GetValue(_messTypeProperty).ToString(); }
set { SetValue(_messTypeProperty, value); }
}
Add a name to your control in XAML:
<UserrControl x:Class="myNamespace.MessageUC"
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"
x:Name="MyUserControl">
In the XAML definition of your MessageUC control, in the code where you implement MessType bind it to the property in the code behind. Point to your control using the name you added to the control definition:
MessType="{Binding Path=_messType, ElementName=MyUserControl}"

Related

How to swap a portion of a uwp xaml interface with another on the same page and modify controls?

So I have a user interface which has several controls which I want to persist. One of these controls is a button that is supposed to swap between a view and an edit mode. Each of these will have many controls in them that will need to be accessible later on. My main page is defined as follows, with irrelevant stuff stripped down of course.
MapView.xaml
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
x:Class="TripPhotoMapper.MapView"
mc:Ignorable="d">
<Grid x:Name="grid_main">
<Maps:MapControl x:Name="map_main" MapTapped="MapUserTapped"/>
<StackPanel x:Name="stack_edit_mode">
<Border Tapped="ButtonEditMode">
<TextBlock Text="Edit Mode"/>
</Border>
</StackPanel>
<Grid x:Name="grid_swap_interface">
here is where I want the swapable interfaces
</Grid>
</Grid>
</Page>
MapView.xaml.cs
namespace TripPhotoMapper
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MapView : Page
{
private EditMode _mode_edit;
private ViewMode _mode_view;
private Control _mode_current;
public MapView()
{
this.InitializeComponent();
_mode_edit = new EditMode();
_mode_view = new ViewMode();
_mode_current = _mode_view;
grid_swap_interface.Children.Add(_mode_current);
}
public static class GlobalVars
{
...
//this keeps track on if we are in edit mode
public static bool glo_edit_mode = false;
}
...
private void MapUserTapped(MapControl sender, MapInputEventArgs args)
{
...
//this is the problem
ViewMode.txtblc_view_mode.Text = "hi";
}
//editing controls
private void ButtonEditMode(object sender, TappedRoutedEventArgs e)
{
grid_swap_interface.Children.Clear();
if (GlobalVars.glo_edit_mode == false)
{
_mode_current = _mode_edit;
}
else
{
_mode_current = _mode_view;
}
grid_swap_interface.Children.Add(_mode_current);
}
}
}
I then have two other very barebones xaml files for the two interfaces.
EditMode.xaml
<UserControl
x:Class="TripPhotoMapper.EditMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<Button/>
</Grid>
</UserControl>
ViewMode.xaml
<UserControl
x:Class="TripPhotoMapper.ViewMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TripPhotoMapper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBlock x:Name="txtblc_view_mode" Text="view mode"/>
</Grid>
</UserControl>
I haven't touched the C# for either of these two additional xaml's yet. So they're just like this.
EditMode.xaml.cs
namespace TripPhotoMapper
{
public sealed partial class EditMode : UserControl
{
public EditMode()
{
this.InitializeComponent();
}
}
}
So I've figured out how to swap between the two interfaces without any issue; the button and textblock do both appear as they should. However, I included (for testing) a function to change the text in txtblc_view_mode to "hi", but I'm given the following error:
'ViewMode.txtblc_view_mode' is inaccessible due to its protection level
I'm incredibly new to splitting up files like this and I can't figure out how to fix it. I've found something mentioned in a few posts
x:FieldModifier="public"
but I don't know where to put it. Could anyone help me? Once the interfaces are properly split up, a lot of controls in each will have to be modified in code and thus I'll need to fix this problem.
Can't try this for now but you can check it out.
Add/modify the following code in your ViewMode cs:
public sealed partial class ViewMode : UserControl
{
public static ViewMode Current { get; private set; }
public ViewMode()
{
this.InitializeComponent();
Current = this;
}
}
And maintain the x:FieldModifier="public" in your desired control (TextBlock) to be edited/modified.
<TextBlock x:Name="txtblc_view_mode" x:FieldModifier="public" Text="view mode"/>
On EditMode cs, add in your methods:
public void ChangeTxtBlockText()
{
TextBlock tb = ViewMode.Current.txtblc_view_mode as TextBlock;
if (tb != null)
{
tb.Text = "Hi";
}
}

how to retrieve textbox string form mainpage in uwp?

I am new to UWP.
I have created an app with a MainPage and a UserControl.
I have a TextBox in that UserControl and I want to access its data from my Mainpage.
Can someone suggest a way to do this?
Thanks
While #Peter have a good answer but I think you also can use FieldModifier.
My UserControl is Averieli and my xaml is :
<UserControl
x:Class="Avalonia.Averieli"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Avalonia"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBox x:Name="TextBox" x:FieldModifier="public"></TextBox>
</Grid>
</UserControl>
You can see that I add x:FieldModifier="public" in TextBox that can make it can be used in MainPage.
I use the UserControl in MainPage.
<local:Averieli x:Name="Averieli"></local:Averieli>
I also can use the TextBox in the back code.
public MainPage()
{
InitializeComponent();
Averieli.TextBox.Text = "I can use it";
}
In the constructor of the user control, initialise a static global instance of the UserControl class
public UserControl()
{
//Initialise control
}
public static UserControl UserControlInstance
{
get
{
return m_UserControlInstance ?? new UserControl();
}
}
private static UserControl m_UserControlInstance;
And then just access properties of UserControl via the instance
string x = UserControl.UserControlInstance.TextBox.Text;
This is called a singelton by the way, in case you wanted to look it up!

DependencyProperty Silverlight UserControl

I have read through a few articles on this and I can't see what im doing wrong here could anyone help :)
I have a UserControl called CreateRuleItemView I want to add a Dependency Property on here that I can bind my ViewModel too. So far I have.
public partial class CreateRuleItemView : UserControl
{
public CreateRuleItemView()
{
InitializeComponent();
}
public Boolean ShowEditTablePopup
{
get
{
return (Boolean)this.GetValue(ShowEditTablePopupProperty);
}
set
{
this.SetValue(ShowEditTablePopupProperty, value);
}
}
public static readonly DependencyProperty ShowEditTablePopupProperty = DependencyProperty.Register("ShowEditTablePopup", typeof(Boolean), typeof(CreateRuleItemView), new PropertyMetadata(null, OnShowEditTablePopupChanged));
private static void OnShowEditTablePopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
If I then try to access the property in the User Control Xaml I get:
<UserControl x:Class="Views.Setup.CreateRuleItemView"
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"
d:DataContext="{d:DesignInstance Type=vm:CreateRuleItemViewModel, IsDesignTimeCreatable=False}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" ShowEditTablePopup="{Binding DataContext.ShowEditTablePopup}" >
Error 1 The member "ShowEditTablePopup" is not recognized or is not accessible.
Error 3 The property 'ShowEditTablePopup' does not exist on the type 'UserControl'
Error 2 The property 'ShowEditTablePopup' was not found in type 'UserControl'.
Edit 1:
Ok Managed to get around this by adding the binding in the code behind on my Main window where i setup my view.
Setup.CreateRuleItemView v = new Setup.CreateRuleItemView();
BindingOperations.SetBinding(v, CreateRuleItemView.EditTablePopupProperty, new Binding("EditTablePopup"));
You won't be able to achieve this with a UserControl (I've just tried replacing the <UserControl... partial declaration in XAML with <local:CreateRuleItemView when recreating the code locally, but this results in a circular reference and thus won't compile/will potentially result in a XamlParseException). I'd write a control inheriting from ContentControl to which you can add the property and template it instead (I did this with WPF so the namespaces may differ, otherwise the code will work):
using System;
using System.Windows;
using System.Windows.Controls;
namespace DepPropTest
{
/// <summary>
/// Description of CreateRuleItemView.
/// </summary>
public class CreateRuleItemView : ContentControl
{
public CreateRuleItemView()
{
}
public static readonly DependencyProperty ShowEditTablePopupProperty =
DependencyProperty.Register("ShowEditTablePopup", typeof (bool), typeof (CreateRuleItemView), new PropertyMetadata());
public bool ShowEditTablePopup
{
get { return (bool) GetValue(ShowEditTablePopupProperty); }
set { SetValue(ShowEditTablePopupProperty, value); }
}
}
}
Then you can use it as follows (this example uses WPF by the way, hence Window being the parent control):
<Window x:Class="DepPropTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DepPropTest"
Title="DepPropTest" Height="300" Width="300">
<local:CreateRuleItemView Width="300"
Height="300"
ShowEditTablePopup="True">
<local:CreateRuleItemView.Template>
<ControlTemplate>
<!-- define your control's visual appearance... -->
</ControlTemplate>
</local:CreateRuleItemView.Template>
<TextBox Text="Some content for your view" />
</local:CreateRuleItemView>
</Window>

How do you make a custom XAML User Control bindable?

I am making a simple demo to learn how to create a bindable user control. I have created a simple class:
class Person
{
public string firstName;
public string lastName;
public Person(string first, string last)
{
firstName = first;
lastName = last;
}
}
And a very simple user control:
<UserControl x:Class="Example.ExampleHRControl"
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>
<TextBlock x:Name="textFirstName"></TextBlock>
<TextBlock x:Name="textLastName"></TextBlock>
</Grid>
</UserControl>
What I would like to know is what do I need to do in order to be able to use the user control in context like a normal control. I can add this to the MainWindow:
<local:ExampleHRControl x:Name="Hr1"></local:ExampleHRControl>
and then I can address it through code behind and add the value:
Hr1.textFirstName.Text = "John";
Hr1.textLasttName.Text = "Doe";
I would prefer to be able to create an instance of the class Person and simply bind the control on the main window to the Person class.
A couple things you need to do to make this work.
In your code-behind, add a dependency property for the Person object you want your control to know about:
public static readonly DependencyProperty PersonProperty =
DependencyProperty.Register("Person", typeof(Person),
typeof(ExampleHRControl));
public Person Person
{
get { return (Person)GetValue(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
In your XAML, set up your code-behind as your data context and add the binding to your person object:
<UserControl x:Class="Example.ExampleHRControl"
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"
x:Name="This">
<Grid>
<TextBlock x:Name="{Binding Path=Person.FirstName, ElementName=This}"/>
<TextBlock x:Name="{Binding Path=Person.LastName, ElementName=This}"/>
</Grid>
</UserControl>
Now, whenever the Person property is set, your control will update itself with the First and Last names that are associated to the Person.
what you want to to called Dependancy Property you can bind to it from xaml.
1-create the field
public static readonly DependencyProperty FirstNameProperty =
DependencyProperty.Register(
"FirstName", typeof(Strin),
2-create the property
public String FirstName
{
get { return (String)GetValue(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
3- you can use it in the XAML to bind it or just use it
<local:YourControlName FirstName="john"/>
<local:YourControlName FirstName="{Binding MyFirstName}"/>
use Resharper will help you to make a clean code and have very powerfull IntelliSense

Updating UserControl children in DependencyProperty setter not working

I have a UserControl in my Silverlight application and for some reason, the DependencyProperty of a UserControl is not set if I bind it to a value in the view model. I spent several hours of debugging in a trial-and-error fashion now and I'm all out of ideas what to try next.
I can reproduce the issue in a new Silverlight project with
MainPage.xaml
<UserControl x:Class="SilverlightApplication1.MainPage"
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"
xmlns:local="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<local:MyCtrl HeaderText="{Binding HeaderText}"/>
<TextBlock Text="{Binding HeaderText}"/>
</StackPanel>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Windows.Controls;
namespace SilverlightApplication1
{
public class Vm
{
public string HeaderText
{ get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new Vm() { HeaderText = "My Header" };
}
}
}
MyCtrl.xaml (added as new "Silverlight User Control")
<UserControl x:Class="SilverlightApplication1.MyCtrl"
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"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txtHeader" />
</Grid>
</UserControl>
MyCtrl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class MyCtrl : UserControl
{
public MyCtrl()
{
InitializeComponent();
}
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), null);
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set
{
// NEVER CALLED
SetValue(HeaderTextProperty, value);
this.txtHeader.Text = value;
}
}
}
}
The rest of the project is used "as is", i.e. no compiler options were changed and the server part is also left "as is".
Observations:
I see that the getter of Vm.HeaderText is called during a binding
operation but the setter of the DependencyProperty MyCtrl.HeaderText is never called.
The TextBlock in MainPage below the custom control displays the bound value correctly.
There are no compiler warnings.
There are no exceptions thrown.
There are no debug outputs while the application runs.
This feels like something important is silently failing where it shouldn't.
Maybe I can shed some light on your observations and assumptions:
You can update child controls inside a DependencyProperty setter. Call your setter and see for yourself, the update will be performed. You falsely assume the binding engine is obliged to call your setter. Well, it just calls SetValue(HeaderTextProperty, newValue); on your control, no need to call the setter.
Your observation is specified behaviour.
As you figured out, the right way to do it is to use a propertyChanged callback.
The property getter on your viewmodel Vm.HeaderText is called by the binding engine, because your viewmodel is no DependencyObject and HeaderText is no DependencyProperty so there is no SetValue(...) and no GetValue(...)
You can't see any compiler warnings or exceptions, nor is anything silently failing, because there is nothing wrong with your scenario.
Well, seems like you cannot update the child controls inside a DependencyProperty setter (would be interesting to know why and if this is specified behaviour...)
Using this instead works:
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), new PropertyMetaData(OnHeaderTextChanged));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
private static void OnHeaderTextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var ctrl = d as MyCtrl;
ctrl.txtHeader.Text = (string)e.NewValue;
}

Categories