FocusedElement is not being honoured - c#

I have created a basic application using Prism & MVVM. So far, it only consists of the Shell, and one View/ViewModel.
During application load, I am loading the View into my main region and this displays on screen. This works, but I cannot get the textbox on the view to focus. It looks like the cursor is in the box (although it's not flashing), but it doesn't accept text input until I click on the textbox.
I've recreated this in a new project, where all I've done is install prism/prism.unityextensions, set up the shell and the view, and loaded the view into the shell region. Neither xaml file has anything in the code behind.
Shell
<Window x:Class="MVVMFocusTest.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://www.codeplex.com/prism"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DockPanel LastChildFill="True">
<ContentControl Name="MainRegion" DockPanel.Dock="Top" prism:RegionManager.RegionName="MainRegion" />
</DockPanel>
</Grid>
</Window>
View1
<UserControl x:Class="MVVMFocusTest.View1"
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">
<StackPanel>
<Grid FocusManager.FocusedElement="{Binding ElementName=Username}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">Username</Label>
<TextBox Name="Username" Grid.Row="0" Grid.Column="1" ToolTip="Enter Username" TabIndex="0" />
<Label Grid.Row="1" Grid.Column="0">Password</Label>
<PasswordBox Grid.Row="1" Grid.Column="1" Name="LoginPassword" PasswordChar="*" ToolTip="Enter Password" TabIndex="1" />
</Grid>
</StackPanel>
</UserControl>
Can anyone point out what I'm doing wrong? As far as I'm aware, the FocusManager.FocusedElement="{Binding ElementName=Username}" should be sufficient to set the focus.

As per FocusManager documentation -
Logical focus pertains to the FocusManager.FocusedElement within a
specific focus scope.
So, its not necessary that element with logical focus will have keyboard focus as well but vice versa is true i.e. element with keyboard focus will surely have a logical focus as well.
As stated in documentation FocusManager.FocusedElement guarantees logical focus and not keyboard focus. So what you can do is create an attach behaviour similar to FocusManager.FocusedElement which will set keyboard focus on an element.
You can refer to this for setting keyboard focus using attached behaviour - Setting keyboard focus in WPF.
Code from that article -
namespace Invoices.Client.Wpf.Behaviors
{
using System.Windows;
using System.Windows.Input;
public static class KeyboardFocus
{
public static readonly DependencyProperty OnProperty;
public static void SetOn(UIElement element, FrameworkElement value)
{
element.SetValue(OnProperty, value);
}
public static FrameworkElement GetOn(UIElement element)
{
return (FrameworkElement)element.GetValue(OnProperty);
}
static KeyboardFocus()
{
OnProperty = DependencyProperty.RegisterAttached("On", typeof(FrameworkElement), typeof(KeyboardFocus), new PropertyMetadata(OnSetCallback));
}
private static void OnSetCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var frameworkElement = (FrameworkElement)dependencyObject;
var target = GetOn(frameworkElement);
if (target == null)
return;
frameworkElement.Loaded += (s, e) => Keyboard.Focus(target);
}
}
}
Use in XAML -
<UserControl xmlns:behaviors="clr-namespace:Invoices.Client.Wpf.Behaviors">
<Grid behaviors:KeyboardFocus.On="{Binding ElementName=TextBoxToFocus}">
<TextBox x:Name="TextBoxToFocus" />
</Grid>
</UserControl>

FocusManager.FocusedElement="{Binding ElementName=Username}" sets logical focus but not physical focus.
Physical focus is the normal focus, logical focus is kinda a second focus which is still a little bit buggy in wpf 4.0.
I would suggest you to use Keyboard.Focus(this.Username).

Related

Modify textblock of a UserControl from another UserControl WPF

i have a UserControl that contains a TextBox now i am loading another UserControl that contains a TextBlock .When the button is clicked, I want to assign value entered in TextBox to TextBlock of another control that is loaded. How can i do this ?
Main UserControl
<UserControl x:Class="IntelliVentory.UserControls.CategoryControl"
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="670" d:DesignWidth="1100">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="CategoryNameBox" Width="350" />
<Button Grid.Row="1" Click="AddCategoryFunc">Load Another Control</Button>
<Grid Grid.Row="2" Name="CategoriesWraper"></Grid>
</Grid>
</UserControl>
Another UserControl
<UserControl x:Class="IntelliVentory.UserControlModules.CategoryModule"
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:IntelliVentory.UserControlModules"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Name="CategoryName" FontSize="12" FontWeight="Thin">Category Name Here</TextBlock>
</Grid>
</UserControl>
Main UserControl.cs
Loading another UserControl.
private void AddCategoryFunc(object sender, RoutedEventArgs e)
{
UserControl categoryMod = new CategoryModule();
CategoriesWraper.Children.Add(categoryMod);
}
You want to have something like
categoryMod.CategoryNameValue = categoryControl.CategoryNameValue;
So you need to define two properties, one CategoryNameValue property with which you get the Text value of the TextBox, and one CategoryNameValue property with which you can set the Text property of the TextBlock.
Define this property in the CategoryControl class,
public string CategoryNameValue { get { return CategoryNameBox.Text; }
And this in CategoryModule class,
public string CategoryNameValue { set { CategoryName.Text = value; }
And you can start using them in your code.
You can define them as Dependency Properties instead of plain CLR properties, and then look to use data binding. With data binding both user controls can be bound to the same data model so their values are synced automatically.
Edit:
Turns out you can access a UserControl's child elements from outside as if they are public fields. That is, you can write code like this without having to define new properties
CategoryModule categoryMod = new CategoryModule();
categoryMod.CategoryName.Text = CategoryNameBox.Text;
CategoriesWraper.Children.Add(categoryMod);

Update the TextBox.Text in Usercontrol from everywhere

I'm facing an issue that seems recurrent and with a lot of solutions but, I apologize, I cannot/not able apply in my case. Let me summarize the topology: I have a main windows (MainWindow) with a grid and, in the bottom cell I put an user control written by me (UC_StatusMonitor) with a textbox inside the user control (LBL_CONN_Message) where I want to update with result of operations (e.g. "Connected to device X", "Impossible to read data from Y", "Missing fields" etc etc). This is basically used to inform the user if something is right or wrong. I understood I have to use Dependancy to solve this issue but my implementation doesn't work (for sure I missed something).
Let me show the code:
MainWindows.xaml
<Window x:Class="LUX.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:LUX"
mc:Ignorable="d"
Title="LUX" Name ="MainForm" Height="600" Width="800" MinHeight="600" MinWidth="800">
<Border Padding="10">
<Grid Name="Main_Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<!-- others controls .... -->
<!-- Monitor -->
<StackPanel Name="Stack_Monitor" Grid.Row="2" Grid.Column="1">
<Grid Name="BottomBar" Height="20">
<local:UC_StatusMonitor Height="100" Grid.Row="2" Grid.Column="1"/>
</Grid>
</StackPanel>
</Grid>
</Border>
</Window>
Then the code for the Control
UC_StatusMonitor.xaml
<UserControl x:Class="LUX.UC_StatusMonitor"
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:LUX"
mc:Ignorable="d"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
d:DesignHeight="20" d:DesignWidth="300">
<Grid Name="UCR_Base" Background="White">
<WrapPanel>
...
<TextBox Name="LBL_CONN_Message" Margin = "10 0 0 0" VerticalAlignment="Center" IsReadOnly="True" BorderThickness="0" Text="{Binding MyTextProperty, ElementName=control}"/>
...
</WrapPanel>
</Grid>
</UserControl>
UC_StatusMonitor.xaml.cs
namespace LUX {
/// <summary>
/// Interaction logic for StatusMonitor.xaml
/// </summary>
public partial class UC_StatusMonitor : UserControl
{
Button[] MenuButtons;
//// The dependency property which will be accessible on the UserControl
public static readonly DependencyProperty MyTextPropertyProperty = DependencyProperty.Register("MyTextProperty", typeof(string), typeof(UC_StatusMonitor), new UIPropertyMetadata(String.Empty));
public string MyTextProperty
{
get { return (string)GetValue(MyTextPropertyProperty); }
set { SetValue(MyTextPropertyProperty, value); }
So, I'm expecting that, everywhere (in all the classes into the workspace, I declared a status monitor static object), I should use an instruction like
MyTextProperty = "Connected";
and then see this message on the textbox into user control.
Obviously, doesn't happen :(
Thanks and best regards
I have managed to get the UserControl to work with Binding.
Here is how I have done it:
UserControlWithBinding.xaml:
<UserControl x:Class="SO_app.UserControlWithBinding"
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:SO_app"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="300">
<Grid Name="IAmGroot"> <!-- Name this grid as you want as this is what we will use for internal Binding -->
<TextBlock Text="{Binding Status}"/><!-- Because this grid is bound to the control it self you will always use this property, unless you rename it :-) -->
</Grid>
Now the code behind of the UserControlWithBinding.xaml.cs:
/// <summary>
/// Interaction logic for UserControlWithBinding.xaml
/// </summary>
public partial class UserControlWithBinding : UserControl
{
public UserControlWithBinding()
{
InitializeComponent();
IAmGroot.DataContext = this;// this is where we set the data context for the grid so it uses the UserControl and not the inherited one. This will allow us to have the DataContext for User Control to be still inherited but the grid will look into a UserControl as an object to assign it to it's data context.
}
public string Status
{
get { return (string)GetValue(StatusProperty); }
set { SetValue(StatusProperty, value); }
}
// Using a DependencyProperty as the backing store for Status. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(UserControlWithBinding), new PropertyMetadata(null));//note that I am using null and not string.Empty
}
Now let's use our control in xaml:
<local:UserControlWithBinding Status="{Binding PropertyThatYouWantToBindThisControlsText}"/>
This should solve your problem.

expose a field in wpf user control for external use

I am very new to wpf and I would like to create a simple user control that consists of a textblock and a textbox so that I can reuse it. However, I do not really know how to bind the content of the textblock so that it can be set from outside and expose the textbox so that it could be bound to other field from the outside calling xaml.
The following is the code for my user control
<UserControl x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
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:WPFLib.UserControlLibs"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="300">
<StackPanel Orientation='Horizontal'
Width='{Binding ActualWidth, ElementName=parentElementName}'
Height='{Binding ActualWidth, ElementName=parentElementName}'>
<Grid HorizontalAlignment='Stretch'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width='1*' />
<ColumnDefinition Width='1*' />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text='{Binding Text, ElementName=parentElementName}'
Background='Aqua'
Grid.Column='0'
Grid.Row='0' />
<TextBox x:Name='UserTxBox'
Grid.Column='1'
Grid.Row='0'
Background='Red'
HorizontalAlignment='Stretch'
Text='this is a test to see how it works' />
</Grid>
</StackPanel>
</UserControl>
How do I expose the Text from the TextBlock and TextBox so that it could be set and retrieved from the calling xaml?
For example
<Window x:Class="TestWPF.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:TestWPF"
xmlns:controls='clr-namespace:WPFLib.UserControlLibs'
` mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525"
WindowState='Maximized'
FontSize='18'>
<StackPanel>
<controls:TextBoxUsrCtrl Width='500' HorizontalAlignment='Left' **Text='NEED TO SET THE TEXT BLOCK HERE'**/>
</StackPanel>
</Window>
You should give it two dependency properties, one for each of the two text properties you want to expose (this is a horrible amount of boilerplate; I use Visual Studio's snippet feature to generate it all). Then in the UserControl XAML, you bind control properties to those.
public partial class TextBoxUsrCtrl : UserControl
{
public TextBoxUsrCtrl()
{
InitializeComponent();
}
#region Text Property
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(String), typeof(TextBoxUsrCtrl),
new FrameworkPropertyMetadata(null) {
// It's read-write, so make it bind both ways by default
BindsTwoWayByDefault = true
});
#endregion Text Property
#region DisplayText Property
public String DisplayText
{
get { return (String)GetValue(DisplayTextProperty); }
set { SetValue(DisplayTextProperty, value); }
}
public static readonly DependencyProperty DisplayTextProperty =
DependencyProperty.Register(nameof(DisplayText), typeof(String), typeof(TextBoxUsrCtrl),
new PropertyMetadata(null));
#endregion DisplayText Property
}
XAML. I simplified this so the layout works as I think you intended.
Note how the bindings use RelativeSource={RelativeSource AncestorType=UserControl} to bind to the dependency properties we defined above on the UserControl. By default, Binding will bind to properties of UserControl.DataContext, but we're not using that. The reason is that if we set UserControl.DataContext here, that will break the viewmodel property bindings in the final XAML fragment at the end of this answer. Those bindings will look for those properties on our control. There are workarounds but it gets ugly. The way I've done it here is best because it never breaks anybody's assumptions about DataContext inheritance.
<UserControl
x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
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:WPFLib.UserControlLibs"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="300"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width='*' />
<ColumnDefinition Width='*' />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Text='{Binding DisplayText, RelativeSource={RelativeSource AncestorType=UserControl}}'
Background='Aqua'
Grid.Column='0'
Grid.Row='0'
/>
<TextBox
x:Name='UserTxBox'
Grid.Column='1'
Grid.Row='0'
Background='Red'
HorizontalAlignment='Stretch'
Text='{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}'
/>
</Grid>
</UserControl>
Usage in window, bound to viewmodel properties:
<local:TextBoxUsrCtrl
Text="{Binding TestText}"
DisplayText="{Binding ShowThisText}"
/>
Lastly, I'm not sure what you were getting at with ElementName=parentElementName. If that's meant to be a reference to a parent control, you can't do that, and it wouldn't be a good idea if you could. You wouldn't want a UserControl constrained by a requirement that a parent control must have a particular name. The answer to that requirement is simply that controls in XAML are only responsible for sizing themselves if they have a fixed size. If they should size to the parent, the parent is always the one responsible for that. So if you want to size two instances of TextBoxUsrCtrl to two different parents, that's fine. Each parent sizes its own children as it pleases.

WPF Grid Elements not resizing when another one is set to collapsed

I am using a Grid to balance 3 parts. The first two shall take up each 50% of the remaining space, the last two shall stay the same height at the bottom, as it is a bar with buttons.
I use a GridSplitter to allow dynamic resizing between the first two elements, but removing it doesnt change anything either.
Here is a minimal working example:
XAML:
<Window x:Class="TestWPFApplication.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:TestWPFApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="rootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox
x:Name="firstBox"
Grid.Row="0"
AcceptsReturn="True"
AcceptsTab="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"/>
<GridSplitter x:Name="splitter" Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
<TextBox
x:Name="secondBox"
Grid.Row="2"
AcceptsReturn="True"
AcceptsTab="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"/>
<Button Grid.Row="3" Content="Collapse" Click="Button_Click"/>
</Grid>
</Window>
CS:
namespace TestWPFApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
splitter.Visibility = Visibility.Collapsed;
secondBox.Visibility = Visibility.Collapsed;
}
}
}
After clicking the button, the second textbox and the gridsplitter collapse, so I cannot use them anymore (desired), but the remaining textbox does not take up the rest of the space (undesired).
In my understanding as the row has a star for height, it should automatically adjust its space. Do I need to call a function like updateUI or something so that the first textbox gets automatically resized?
You observe such behaviour, cause the heights of first and third grid row is set to '*'. After setting 2nd textBoxVisibility to collapsed 3rd grid row is not disappears. So if you write in Button_Click event handler something like this, all should work like expected.
rootGrid.RowDefinitions[2].MaxHeight = 0;
I can suggest to use DataBinding for it property to achieve this. You can bind second TextBox Visibility property to third RowDefinition MaxHeight property with ValueConverter. But I don't know the restrictions of your project.

Interaction between two usercontrols in WPF without using MVVM

I have two UserControls in my application, both of them reside on the MainWindow. Now I need to interact between these two, so that when I click Button in UserControl1, the Text property of the TextBlock in UserControl2 changes.
How can I achieve this without MVVM? I would love to see the MVVM solution though if it is complete cause I'm totally new to it and it is very overwhelming.
MainWindow:
<Window x:Class="WpfApplication23.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:wpfApplication23="clr-namespace:WpfApplication23">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<wpfApplication23:UserControl1/>
<wpfApplication23:UserControl2 Grid.Row="1"/>
</Grid>
</Window>
UserControl1:
<UserControl x:Class="WpfApplication23.UserControl1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<Button Content="Change Text"
Width="200"
Height="80"
Click="ButtonBase_OnClick"/>
</Grid>
</UserControl>
UserControl2:
<UserControl x:Class="WpfApplication23.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBox Width="100" Height="20"/>
</Grid>
</UserControl>
Click Event for Button:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// Access the TextBlock in UserControl2 and Change its Text to "Hello World"
}
To do this without MVVM, you will need to do the following:
Set up an event like "UpdateText" on the first user control, have the button's click method raise this event.
public event Action<string> UpdateText;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// Access the TextBlock in UserControl2 and Change its Text to "Hello World"
if (UpdateText != null)
UpdateText("HelloWorld");
}
Listen to the event in MainWindow that then calls a function on the second user control to update the textblock. Something like:
public MainWindow()
{
InitializeComponent();
myUserControl1.UpdateText += HandleUpdateText;
}
private void HandleUpdateText(String newText)
{
myUserControl2.SetText(newText);
}
Now the right answer to do this would be to use MVVM, but the code sample required would be too long for StackOverflow. I will provide the steps however:
Set up a DependencyProperty on the second user control for the "Text" property, and bind to it:
<UserControl x:Class="WpfApplication23.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBox Width="100" Height="20" Text="{Binding ControlText}"/>
</Grid>
</UserControl>
Put an ICommand dependency property on the first user control that will be invoked on the button click. Bind a function to it on MainWindow that will set the ControlText property to the parameter object.
Probably not the best "First MVVM" sample, as it requires a few advanced concepts (commanding and dependency properties), but it shouldn't be too hard to implement.

Categories

Resources