How to pass data from user control to main control in wpf - wpf

I have status bar control in the main winodw. I have a user control placed in the main window.My user conrtorl has buttons .
say if i click the button in the user control ,I need to update the main window status bar .
I am following MVVM pattern. I am not sure how to achive this. I am beginner in wpf.

You need to use Dependency Property to send something to Main Control from UserControl.
For eg: If you want to change the text of a textblock present in the Main Window from a button Click present in USerControl.
You need to bind your DependencyProperty to the TextBlock TEXT property to reflect the change and your USERCONTROL must Implement INotifyPropertyChange
Make this DependencyProperty in your UserControl
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("WriteText", typeof(string), typeof(UserControlnameSpace)) //Write Namespace of your UserControl where I mentioned
public string WriteText
{
get { return (bool)GetValue(TextProperty ); }
set
{
SetValue(TextProperty , value);
}
}
ButtonClick event present in USERCONTROL
public void Button_Click(object sender, RoutedEventArgs e)
{
WriteText="Hie"; //Write what you want to display on MainWindow.
}
ViewModel:-
private string _txtContent;
public string TxtContent
{
get
{
return _txtContent;
}
set
{
_txtContent = value;
RaisePropertyChanged("TxtContent");
}
}
Main Window:-
<TextBlock Text="{Binding TxtContent,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
Where you are including your UserControl:-Include this property
<UserControl WriteText={Binding TxtContent Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

You can set the DataContext(viewmodel) of the user control same as that of Main Window. Keep a property in viewModel and Bind that Property in the user control. So whenever anything changes in the Control that property will automatically be updated in the View Model which can be used by the Main

I would suggest that the usercontrol works with its own viewmodel. The main windows has a main controller which is responsible to initialize a Status bar messenger service and the user control view model uses that service.
User control's view model is bound to the button's actions via RelayCommand and on executing action it uses the status bar service to update the status.
This is enable your status bar on the main window to work with multiple user controls/pages of your application.

Related

wpf and mvvm: link 2 user controls

Like described in the title, i'd like to link 2 users control.
one is a list and an other one is detail of list.
I'd like to refresh the detail user control depending on the row selected in my first user control
Are there a way to do this?
You could have a DependencyProperty on the "List" control which exposes the selected item. Then bind this as the DataContext of the second control.
public YourType SelectedItem
{
get { return (YourType)this.GetValue(SelectedItemProperty); }
set { this.SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
"SelectedItem", typeof(YourType), typeof(YourListControl));
WPF something like:
<local:YourListControl SelectedItem={Binding SelectedRow, Mode=TwoWay}/>
<local:DetailControl DataContext={Binding SelectedRow}/>
Where SelectedRow would be on your viewmodel
i'm really disapointed with your solutions.
it's difficult for me to understand how it communicates between both usercontrol.
throw the viewmodel containing the usercontrol or the view?
Do you have a minimal sample that i could learn and test for my case?

WPF MVVM Bind User Control to Main Window View Model

I asked a similar question a while back here WPF MVVM User Control. I got some answers, but they were way off, so I guess I wasn't clear in what I want to do....
I am working on a WPF application using MVVM. The app is built using a component based approach, so I have some user controls that I've defined that will be used throughout the application. As an example, I have an Address control. I want to use it an multiple places throughout the application. Here's an example. See here:
http://sdrv.ms/1aD775H
The part with the green border is the Address control. The control has its own View Model.
When I place it on a window or other control, I need to tell it the PK of the customer to load addresses for. So I created a Customer ID DependencyProperty:
public partial class AddressView : UserControl
{
public AddressView()
{
InitializeComponent();
}
public static DependencyProperty CustomerIdProperty = DependencyProperty.Register("CustomerId", typeof(int), typeof(AddressView),
new UIPropertyMetadata(0, AddressView.CustomerIdPropertyChangedCallback, AddressView.CustomerIdCoerce, true));
public int CustomerId
{
// THESE NEVER FIRE
get { return (int)GetValue(CustomerIdProperty); }
set { SetValue(CustomerIdProperty, value); }
}
private static void CustomerIdPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
// THIS NEVER FIRES
AddressView instance = (AddressView)d;
instance.CustomerId = (int)args.NewValue;
}
enter code here
private static object CustomerIdCoerce(DependencyObject d, object value)
{
return value; // <=== THIS FIRES ON STARTUP
}
}
Then in the MainWindowView I have:
<vw:AddressView Grid.Row="1"
Grid.Column="0"
x:Name="AddressList"
CustomerId="{Binding ElementName=TheMainWindow, Path=SelectedCustomer.Id, Mode=TwoWay}"/>
Note my comments in the user control's CS. The Coerce fires on startup. The callback never fires, nor do the CustomerId getter or setter.
What I would like to happen seems simple, I just can't make it work....
When a customer is selected the CustomerId should be passed to the Address UserControl. Then in the VM for the Address UserControl should handle getting & saving the data.
So, again, 2 questions:
1) Anyone see what's wrong?
2) How does the UserControl DP send the PK to the ViewModel?
If anyone's interested, my sample project is here: http://sdrv.ms/136bj91
Thanks
Your CustomerId getter and setter will never fire in this situation. They are there simply as helper methods in case you want to access the CustomerIdProperty property from your code behind.
Your CustomerIdPropertyChangedCallback method will not fire because your binding expression is incorrect. You need to bind to the DataContext of MainWindow and not the window itself:
...
CustomerId="{Binding ElementName=TheMainWindow, Path=DataContext.SelectedCustomer.Id}"
...
Also, make sure that you are calling the INotifyPropertyChanged PropertyChanged event when the property bound to the ComboBox is changed.
Try this :
CustomerId="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.YourSelectedItem.TheProperty}"
I am not sure how to manage your seleted item in window, so please change yourSelectedItem.TheProperty accordingly.

Get reference to nested control's sub control?

MainWindow.xaml has view model MainWindowViewModel.
MainWindow.xaml has a nested User Control called
CustomBrowserControl.xaml
CustomBrowserControl.xaml has a named element webBrowser.
MainWindowViewModel has a command that needs a reference to
webBrowser.
How do I pass the reference?
The Solution I Came Up With
Based on EthicalLogics and sa_ddam213's responses, yes, in the code behind of my MainWindow, if I named the user control (in the xaml, add the attribute x:Name="something"), I could then reference the user control object. I could then pass that reference to the MainWindowViewModel. This is also apparently bad practice, because it breaks MVVM.
So what I did instead
In my user control, I created two new depdency properties as follows:
public static readonly DependencyProperty TakePictureCommand = DependencyProperty.Register("TakePicture", typeof(ICommand), typeof(BrowserControl));
public ICommand TakePicture
{
get { return (ICommand)GetValue(TakePictureCommand); }
set { SetValue(TakePictureCommand, value); }
}
Now in my MainWindow.xaml, I placed a button. I was able to bind the button to the TakePicture command by using the following xaml:
<Window>
<Button Content="Take Picture" Command="{Binding ElementName=browserControl, Path=DataContext.TakePicture}" FocusManager.IsFocusScope="True" ...>
<myUserControls:BrowserControl x:Name="browserControl" ... />
</Window>
This way I didn't need to pass a reference at all, and could just let the command / method in the user control, be invoked by the action on the main window.
Thank you so much to those who responded!!
I don't think its a good practice to have references of Controls in ViewModel in MVVM . But you can create a property of Type WebBrowser Element in ViewModel and assign it like
((MainWindowViewModel)this.DataContext).WebBrowserProperty=CustomBrowserControl.webBrowser
I hope this will help.

Can I add a DependencyProperty on an windows user control?

I'm trying to host a Visio ActiveX object in a WPF application.
To do this, I created a Windows user control project where I add the Visio object. This windows user control is then hosted on an WPF user control in an WindowsFormsHost object.
<WindowsFormsHost Name="wfHost" Grid.Row="1">
<wf:VisioUserControl FileNamePath="?"/>
</WindowsFormsHost>
What I would like to do is to bind the value of the FileNamePath member to the value of a TextBox element which defines the path.
The project follows the MVVM pattern, so there is no way that I can access the VisioUserControl object in my ViewModel.
The solution I was thinking about is to bind the FileNamePath member to the value of the TextBox that contains the path, but it is not a DependencyProperty and it seems that I'm not able to define one in the code behind of the windows user control.
So, is there any workaround to perform this binding?
Thanks in advance.
You can solve this by creating a UserControl that wraps your VisioUserControl (I wrote a simple tutorial on UserControl creation here). You can then add a FileNamePath dependency property to your UserControl. In the property changed handler of this dependency property, set the FileNamePath property on the VisioUserControl that this user control wraps.
Ok I have created an example of a WPF usercontrol that is hosting a Winforms control, with a dependency property that is bound to the winforms control's text property.
public partial class ActiveXObjectHoster : UserControl
{
private static System.Windows.Forms.Label testObject;
public ActiveXObjectHoster()
{
InitializeComponent();
testObject = new System.Windows.Forms.Label();
windowsFormsHost1.Child = testObject;
}
#region Properties
public static DependencyProperty FileNameProperty = DependencyProperty.Register("FileName", typeof(string), typeof(ActiveXObjectHoster), new UIPropertyMetadata("",new PropertyChangedCallback(OnFileNamePropertyChanged)));
public string FileName
{
get { return (string)GetValue(FileNameProperty); }
set
{
SetValue(FileNameProperty, value);
}
}
private static void OnFileNamePropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
testObject.Text = (string)e.NewValue;
}
#endregion
}
Here is the xaml of the control (its very simple)
<UserControl xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
x:Class="WPFTestApp2.Controls.ActiveXObjectHoster"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="ObjectHost"
Height="100" Width="100">
<Grid>
<my:WindowsFormsHost x:Name="windowsFormsHost1" />
</Grid>
</UserControl>
What you need to do is change the test object from a Label to whatever Visio object you were using. Then in the property callback change the text property to the filename or whatever property you wanted.
As mentioned above this is done in the code behind, but that is fine for a user control, its completely decoupled from whatever thing is using it, you just need to bind to the filename property of the control.
Here is a link to a project I created showing how the control is used. There is a textbox whos text is bound to the FileName property, which changes the Winforms Labels text.
You can place this in a Winforms Usercontrol if you want to use it in winforms (like you mentioned in your reply to my comment)
Try replacing the label for your control and see if it works.
Why not implement a UserControl to wrap the WindowsFormHost and the Visio user control? Then you cann add a Dependency Property, and implement in the code behind a handler for the PropertyChangedCallback, and appropiately interact with the WinForms control

Bind a WPF mainWindow TextBox to a variable calculated in a user control C#

I have a textBox on my main Window and I have a user control with Images (Bitmaps). Through a mouse click on an Image, a value is calculated. This value should be displayed on the textBox in the main window.
1) without data binding
How could I access the textBox object on the main window from the user control. It works the other way round, i.e. I can access a user control textBox from the main window using the name of the user control and the textBox to access the textBox such as usercontrol1.textBoxName.
But it seems to me that I cannot access a main window textBox from the usercontrol such as mainWindow.textBoxName because the user control does not know the main Window and has no main Window object. Is this correct?
2) with data binding
It probably works with data binding. But what I tried so far did not work. In the main window XAML:
TextBox Text="{Binding Path=usercontrol1.GetCycleNumber()}" Name="cycleNumberBox"
in mainWindow.cs:
public partial class MainWindow : Window , INotifyPropertyChanged
I added the INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public void CycleChanged()
{
this.cycleNumber = usercontrol1.GetCycleNumber();
if (this.cycleNumberBox.Text != cycleNumber)
{
this.cycleNumberBox.Text = cycleNumber;
RaisePropertyChanged("cycleNumber");
}
}
usercontrol1.cs
Now I would have to signal a change with
RaisePropertyChanged("cycleNumber");
in the user control. However, I cannot access this method.
Since I spent days already to figure this out, I would be glad for any help.
I am beginner and it is my first project. Thank you!
If you have a user control that needs to share a piece of data with main window (or for any container of the user control), your best bet is to use data binding.
Expose a dependency property on the user control. In your case, it looks like CycleNumber.
Internally,the user control can use this dependency property as needed. If it's a calculated field, you may want to use the RegisterReadOnly() method to register the dependency property.
2a. To have other controls access the value in CycleNumber, you can either use ElementBinding to bind to the dependency property, or
2b. have the dependency propery bound to a value in your ViewModel (or other structure if you're not following the MVVM pattern).
If you need more to go on, I can come up with some sample code for you.
Hope that helps.
Sergio

Resources