How to pass data from MainWindow to a User Control that's inside the MainWindow?
A UserControl should never have a "private" view model, as you assign it to the DataContext in the UserControl's XAML. It should instead expose dependency properties that could be bound to properties of an externally provided view model object.
Declare an ItemsSource
property like this:
public partial class UserControl1 : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(
nameof(ItemsSource), typeof(IEnumerable), typeof(UserControl1));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public UserControl1()
{
InitializeComponent();
}
}
And bind the ListView like this:
<UserControl ...>
...
<ListView ItemsSource="{Binding ItemsSource,
RelativeSource={RelativeSource AncestorType=UserControl}}">
...
</ListView>
...
</UserControl>
When you use the UserControl, bind the property to a view model property:
<TabItem Header="UC1">
<local:UserControl1 ItemsSource="{Binding OrderList}"/>
</TabItem>
The last XAML snippet assumes that the object in the UserControl's DataContext has a OrderList
property. This would automatically happen when the TabControl is bound to a collection of view model objects with that property.
Alternatively, let the elements in the UserControl's XAML directly bind to the properties of the object in the inherited DataContext.
<UserControl ...>
...
<ListView ItemsSource="{Binding OrderList}">
...
</ListView>
...
</UserControl>
Your control would not have to expose additional bindable properties, but it would only work with DataContext objects that actually provide the expected source properties.
WPF Passing data object from Main application UI to user control
Since the UserControl are defined in XAML and are initialized by the code InitializeComponent of your MainWindow your are not able to use a constructor to pass a reference of your SensorDevice to the UserControls.
Add a property SensorDevice
to your UserControls AlsTabUC
and rangingTabUC
to pass a reference of your SensorDevice to your UserControls after InitializeComponent
is called in your MainWindow.
public SensorDevice Sensor {
get;
set;
}
Change the constructor of your MainWindow
to the following
public MainWindow()
{
m_mySensorDevice = new SensorDevice();
InitializeComponent();
// Pass reference of SensorDevice to UserControls
rangingTabUC1.Sensor = m_mySensorDevice;
alsTabUC1.Sensor = m_mySensorDevice;
}
In your UserControls you can use the property to call the methods on your SensorDevice
SensorDevice.readAmbientLight();
or
SensorDevice.readRange();
How to pass shortcuts from MainWindow to the UserControl in ContentControl?
If you want the UserControl
to be able to handle all key presses in the window, you could get a reference to the parent window using the Window.GetWindow
once the UserControl
has been loaded and then hook up an event handler to it:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
Loaded += (s, e) =>
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
};
Unloaded += (s, e) =>
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown -= ParentWindow_PreviewKeyDown;
};
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
//do something...
}
}
Accesing properties in a UserControl from the MainWindow (WPF/MVVM)
MainWindowVMInstance.UserControlVMInstance.Property
The UserControl
is inside your MainWindow
.
Therefore your MainWindow
has a property (/instance) of your UserControlVM
.
Note: If you also need a reference of MainWindowVM
inside your UserControlVM
, pass it to the constructor and store it as property.
In xaml it would look like this (inside MainWindow.xaml
):
<ContentControl Content="{Binding UserControlVMInstance}"/>
Don't forget the DataTemplate
:
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
Edit after question update:
This is an example with a part of your code to demonstrate WPF and MVVM in action. You simply define a DataTemplate
in your UserControl.Resources
and then give the ContentControl
via Binding
an instance of your UserControlVM
. WPF knows there's a DataTemplate
for this type and will add an instance of the UserControlView
where the ContentControl
is.
<MainWindow>
<MainWindow.Resources>
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
</MainWindow.Resources>
<!-- Your TabControl -->
<TabControl>
<!--Result View-->
<TabItem Header="{Binding TabImportHeader}">
<ContentControl Content="{Binding TabImportCONTENT}"/>
</TabItem>
</TabControl>
</MainWindow>
How to passing value from window to usercontrol at runtime?
The UserControl
is created before the GetMyValue
property is set. You cannot set a property of an instance before you have created it...
Wait until the UserControl
has been loaded and you will get the value as expected:
public UserControl1()
{
InitializeComponent();
Loaded += (s, e) =>
{
string finalValue = GetMyValue;
};
}
Passing data to user control in MVVM pattern
You are instantiating the UserControl1 object twice:
Once within the XAML. The <uc:UserControl1> element instantiates a UserControl1 object, using the default constructor, and assigns it to the member ucControl.
You instantiate it again within the constructor of the MainWindow object
If you put a break point in the constructor of UserControl, you'll notice it is called twice. I assume WPF instantiate and initialize the XAML's UserControl (#1 from above) after you assign the dynamic UserControl (#2 from above), and this is why you see the former in the logical tree of MainWindow.
You should have only one instance. If you want to parameterized a user control, the canonical paradigm is what you mention that you don't want to do (why??). If you had such a property, you could set it in the XAML: <uc:UserControl1 x:Name="..." YourProperty="NameSet>
exposing such a property is a single line in the UserControl:
public YourProperty { get; set; }
If you insist of not having this line, you should do the following:
- Remove the XAML's user control.
- In main window, subscribe to the Loaded event
- In the handler of the Loaded event, instantiate a new UserControl1 - with whatever constructor parameter that you want.
- Manually add it to the Children array of the parent Grid element
Clearly this isn't my recommendation. In addition to the complexity, with the former method you'll also work very well with the Visual Studio designer.
Related Topics
Accessing UI Control from Backgroundworker Thread
How to Return an Anonymous Type from a Method
How to Debug a Referenced Dll (Having Pdb)
Serializing an Object as Utf-8 Xml in .Net
Implementing Collectionchanged
How to Programmatic Disable C# Console Application's Quick Edit Mode
Wpf - How to Create Menu and Submenus Using Binding
Loading a Full Hierarchy from a Self Referencing Table with Entityframework.Core
Help with a Oledb Connection String for Excel Files
Binding Listbox to List<Object> in Winforms
How to Sort a String of Text Followed by a Number Using Linq
How to Initialize a C# Dictionary with Values
Distinct in Linq Based on Only One Field of the Table
Illustrating Usage of the Volatile Keyword in C#
How to Show File Copy Progress Using Fileinfo.Copyto() in .Net