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!
Related
In a more complex implementation of the below, I discovered a strange behavior.
I have a window, containing a UserControl. The UserControl requires a constructor with parameters, and is therefore reinitialized after the Window has called InitializeComponent().
Control XAML
<UserControl x:Class="TEMP5.MyControl"
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="33" d:DesignWidth="48">
<Grid>
<Button Content="Click"
Width="40" Height="25" Margin="4"
Click="Button_Click"/>
</Grid>
</UserControl>
Control C# code
public partial class MyControl : UserControl
{
public string Foo { get; set; }
public MyControl()
{
InitializeComponent();
}
public MyControl(string foo): this()
{
Foo = foo;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine($"This method was invoked on: {this.GetHashCode()} with Foo value: \"{Foo}\"");
}
}
Window XAML
<Window x:Class="TEMP5.MainWindow"
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:TEMP5"
mc:Ignorable="d"
Title="MainWindow" Height="auto" Width="auto">
<local:MyControl x:Name="myControl"/>
</Window>
Window C# code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Console.WriteLine($"Parameter-less constructor creates control: {myControl.GetHashCode()}");
myControl = new MyControl("Bar");
Console.WriteLine($"Control is now referenced: {myControl.GetHashCode()} with Foo: {myControl.Foo}");
}
}
Console Output
Parameter-less constructor creates control: 66824994
Control is now referenced: 5560998 with Foo: Bar
Clicks the button
This method was invoked on: 66824994 with Foo value: ""
Question
Why is the UserControl instance not changed? The console output shows that the field is updated to reference the result of the "parametered" constructor, yet the button click is invoked on the original instance.
With credit and thanks to #Clemens for the answer provided in comments above. In summary:
Recommendation is to avoid property assignment through a constructor in place of an implementation that allows for reassignment. Suggestion to consider data templating as per: C# WPF content switching.
The observed behavior is due to the fact that the myControl field does not make reference to an instance assigned to the Content property of the Window.
Replacing myControl = new MyControl("Bar"); with Content = new MyControl("Bar"); would result in the expected behavior. However, again, this is not the recommended approach.
Thank you also to #MindSwipe for their contribution.
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";
}
}
I have a uCtrl of type UserControl in a parentPg of type Page (instead of a Window). And I want to access that parentPg in uCtrl class so that I can bind some uCtrl's property to parentPg's Control.
Like as we get in case of Window.
public partial class uCtrl : UserControl
{
Window parentWin;
public uCtrl()
{
parentWin = Window.GetWindow(this);
}
public bool IsPrptReady
{
get
{
//accesing parent Window's control
if (((pWin)(parentWin)).txt.Text != "")
{
return true;
}
else
{
return false;
}
}
}
}
In above code snippet, I am getting parent Window (i.e. of type pWin) in uCtrl of type UserControl and then sets its Property (i.e IsPrptReady) based on parents Window's Control i.e. txt of type 'TextBox'.
I want to do the same thing, but in case of Page not Window.
I have seen a lot of questions like this but nothing solves my problem.
Any help will be appreciated.
The XAML code is as below.
<Page x:Class="Stego.Pages.EnDeCoding"
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:Test"
xmlns:userControls="clr-namespace:Test.UserControls"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800"
>
<Grid>
<userControls:uCtrl x:Name="uCtrlName"/>
</Grid>
</Page>
The second answer in the question you linked to provides the answer you need; specifically the use of the VisualTreeHelper.
Alternatively, you could add a [dependency] property to the user control of type Page and bind the property to the page instance the control is hosted within. Something like:
<Page x:Name="page">
<local:UCtrl Page="{Binding ElementName=page}"/>
</Page>
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}"
I have some problems with a WPF custom control, I'm trying to make it work but just don't get it:
Here is my problem, I'm creating a simple custom control that's almost the same to a TextBox. This control has a dependency property named "Texto", and the binding between the XAML and back-code of the custom control works fine, here is the code:
<UserControl x:Class="WpfCustomControlLibrary1.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="47" d:DesignWidth="147">
<Grid Height="43" Width="142">
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,8,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Texto}"/>
</Grid>
And the dependency property code:
public static readonly DependencyProperty TextoProperty = DependencyProperty.Register("Texto", typeof(string), typeof(UserControl1));
public string Texto
{
get
{
return (string)GetValue(TextoProperty);
}
set
{
SetValue(TextoProperty, value);
}
}
Ok, now the problem: When I use this control in other windows I try to bind the "Texto" property to a viewmodel (as simple as everything else) but the property on the view model just dont change:
The ViewModel code:
public class ViewModelTest
{
public string SomeText { get; set; }
}
And the code of the applicatoin Window:
public ViewModelTest test;
public Window1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show(test.SomeText);
MessageBox.Show(uc.Texto);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
test = new ViewModelTest();
this.DataContext = test;
}
And the binding with the property of the view model:
<my:UserControl1 HorizontalAlignment="Left" Margin="27,12,0,0" Name="uc" VerticalAlignment="Top" Texto="{Binding Path=SomeText,Mode=TwoWay}"/>
Just for make it clearer, if I write "Hello" in the custom control and then I push the "button1", the first message shows nothing and the second message shows "Hello".
As you can see I'm fairly new into this, so I hope some of you can help me. Thanks.
Your binding Texto="{Binding SomeText}" works fine, the problem is the rebinding from your user control to the inner textbox. Remember binding will ALWAYS, if not modified, refere to the DataContext. But your DataContext doesn't contain the property Texto. Your control has that, To refere to that you need something called TemplateBinding, but this only works when you are in a ControlTemplate. Which you aren't so what is the solution?
You can use a special form of binding, by changing the source from the DataContext to a control with a given name: First give your UserControl a name
<UserControl x:Class="WpfCustomControlLibrary1.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"
x:Name="mainControl"
d:DesignHeight="47" d:DesignWidth="147">
and now change the binding to refere to the control, not the DataContext of the control anymore.
<TextBox Text="{Binding ElementName=mainControl, Path=Texto}"/>
Now your ViewModel binds to your user control and the content of the user control binds to the user controls Texto property.
Also one minor thing, what you called custom control, is in fact a user control, custom controls are something else.