adding custom routed event of user control to xaml of a window in wpf - wpf

I am little new to Command binding so this might be a trivial question to many. I know that we can add Command bindings in xaml of a window and give its correspondng property in viewmodel. This viewmodel will be given to the DataContext of the window. Something like the following
--app.xaml.cs
mainWindow.DataContext = viewModel;
-- xaml
lt;Button Grid.Row="1" HorizontalAlignment="Right" Margin="0,3,18,3" Name="button1" Width="110"
Command="{Binding LoadCommand}">_Load</Button>
-- viewmodel
/// <summary>
/// Gets the load command.
/// </summary>
/// <value>The load command.</value>
public ICommand LoadCommand
{
get
{
if (m_LoadCommand == null)
{
m_LoadCommand = new RelayCommand(param => CanLoad(), param => Load());
}
return m_LoadCommand;
}
}
Here the relaycommand is a class which implements ICommand interface. CanLoad() and Load() are the methods which will get executed for canexecute and execute action of the relaycommand respectively. This is the click event of the button which is handled.
I have a user control which has a custom routedevent registered in it and the user control is then used on a window. I am currently adding the event handler explicitly in code.
//hook up event listeners on the actual UserControl instance
this.ucCustomEvent1.CustomClick += new RoutedEventHandler(ucCustomEvent_CustomClick);
//hook up event listeners on the main window (Window1)
this.AddHandler(UserControlThatCreatesEvent.CustomClickEvent, new RoutedEventHandler(ucCustomEvent_CustomClick));
I dont want to hook up the routedevent explicitly in code but in the xaml in the similar way as in the button example. I have uploaded the working sample code here for your perusal.

I'm not sure I fully understand your question but I hope one of my answers below helps you out.
To attach a "direct" event handler in XAML, just do the following:
<c:MyUserControl x:Name="uc1" CustomClick="uc1_CustomClickHandler"/>
To hook up a handler for the (routed) event of one element (e.g. the CustomClick event in your example) to another element (e.g. the parent window):
<Window c:MyUserControl.CustomClick="ucCustomEvent_CustomClick"/>
Now, if you want to tie up an event in your UI to a Command in your ViewModel, you will need attached behaviors to do that. There are lots of frameworks around featuring different implementations of this. Here's one you can try out: http://sachabarber.net/?p=514. It will allow you to do something like the following in your code:
<c:MyUserControl local:CommandBehavior.RoutedEventName="MyCustomClick"
local:CommandBehavior.TheCommandToRun="{Binding MyViewModelCommand}"/>
Hope this helps.

Related

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.

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

wpf prism (CAL) - Closing Window in Popup Region when the ViewModel knows nothing of the View

We have a Region in the Window tag of our shell, adding things to this region pops out another Window.
<Window x:Class="GTS.GRS.N3.Shell.Shell1"
--removed namespace references for clarity
cal:RegionManager.RegionName="{x:Static Constants:RegionNames.WindowRegion}">
We're adding ViewModels to the Region Manager and then the View is attached via a data context so that the ViewModel knows nothing about the View i.e.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<DataTemplate DataType="{x:Type Model:CommunicationViewModel}">
<v:CommunicationView />
</DataTemplate>
</ResourceDictionary>
My question is how do I close the Pop up Window, I tried removing the ViewModel from the RegionManager - but this exceptions ... the View is a UserControl, but I need to close its Owner which is a new Window opened by the Region. I don't really want to have to hack it via the DataContext of the ViewModel.
Can anyone assist please?
Andy,
It took me quite awhile to figure this one out myself.
The cleanest way to accomplish this is by using the DelegateCommand (or RelayCommand) and adding an event handler in the code that creates the window with window.Show().
// Define the View
Shell window = Container.Resolve<Shell>();
// Define the ViewModel
ShellViewModel windowVM = Container.Resolve<ShellViewModel>();
// When the ViewModel asks to be closed, close the View.
EventHandler handler = null;
handler = (sender, e) =>
{
windowVM.RequestClose -= handler;
window.Close();
};
windowVM.RequestClose += handler;
// Set the ViewModel as the DataContext of the View
window.DataContext = windowVM;
// Display the View
window.Show();
I then use a Composite Event to notify the window's ViewModel (not the UserControl's) that it has a request to close. The assigned subscription handler for the composite event then calls this.OnRequestClose().
In the Constructor for the ViewModel:
//subscribe to composite events
_eventAggregator.GetEvent<WindowCloseEvent>().Subscribe(WindowClose);
In the body of the ViewModel:
/// <summary>
/// Private Event handler for WindowCloseEvent.
/// </summary>
private void WindowClose(bool value)
{
// Close the View
this.OnRequestClose();
}
See Josh Smith's excellent article on MSDN about using the M-V-VM pattern with WPF at http://msdn.microsoft.com/en-us/magazine/dd419663.aspx for more information.
_regionManager.Regions[RegionNames.PopupRegion].Deactivate(_regionManager.Regions[RegionNames.PopupRegion].ActiveViews.FirstOrDefault());

Programmatically triggering the HyperlinkButton navigation

I'm using the Silverlight 3 HyperlinkButton and I want to programmatically trigger the navigation that normally occurs when the button is clicked. There does not appear to be a public method that supports this.
The OnClick method is protected so I could inherit from this control to gain access to this method from a custom control but is there a better way to go about this?
Looking at the implementation of the OnClick method using Reflector does not give me an obvious hint for a better way and the complexity of the code makes me wonder if there is a good reason for not allowing this event to be triggered programmatically. The lowest level managed code call is to MS.Internal.XcpImports.NavigateToSafeURINative and I don't see any public method in the code path that I could use.
For an in browser application, the HtmlWindow.Navigate does the trick as follows, relying on a unique target name to make sure it opens in a different tab or window to the current window hosting the silverlight application.
var hostingWindow = HtmlPage.Window;
hostingWindow.Navigate(siteHyperLinkbutton.NavigateUri, siteHyperLinkbutton.TargetName);
For an out of browser application, the best solution I have found is to derive a very simple custom class from HyperlinkButton and implement a public method that in turn invokes the protected OnClick method as shown below. This custom class can be declared in XAML with the appropriate NavigateUri and TargetName properties, just like the base HyperlinkButton. I was hoping to avoid creating a custom class by invoking the OnClick method via reflection but this not possible due to the Silverlight Security Considerations for Reflection.
public class CustomHyperlinkButton : HyperlinkButton
{
/// <summary>
/// Exposes the base protected OnClick method as a public method.
/// </summary>
public void OnClickPublic()
{
OnClick();
}
}
You could link the button to a Command, then trigger the command anywhere from Code using Command.Execute(). Psuedo code:
XAML:
<UserControl x:Class="ClassName"
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:commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation">
<Button commands:Click.Command="{Binding MyCommand}" />
</UserControl>
CODE (behind or MVVM):
public class ClassName
{
///Class constructor
public ClassName()
{ /// implement the command behaviour as a delegate
MyCommand = new DelegateCommand<object>(
delegate{
/// do your OnClick() behaviour implementation here
}
);
}
private DelegateCommand<object> _myCommand;
public DelegateCommand<object> MyCommand
{
get { return _myCommand; }
set { myCommand=value;
OnPropertyChanged("MyCommand");}
}
/// Another method called from somewhere else in code
void SomeOtherMethod()
{
MyCommand.Execute(null);
}
}
This works particularly well in MVVM world.

Access items inside the DataTemplate in WPF

I was wondering if in WPF you are able to get the actual instances of the datatemplate objects. For example in the following situation:
<UserControl>
<UserControl.Resources>
<DataTemplate x:Key="MyTemplate">
<CustomControl ></CustomControl>
</DataTemplate>
</UserControl.Resources>
<ListBox DataTemplate="{StaticResource MyTemplate}"></ListBox>
</UserControl>
Assume that CustomControl has a CustomEvent and a public CustomMethod. I want to access that event and the public method in the user control. Is this possible? How would I be able to do this? Thanks in advance for any help.
Cheers,
Nilu
You need to find the ContentPresenter holding the ListBox (by navigating the VisualTree) and then use
myDataTemplate.FindName("myCustomControl", myListBox);
There is an example on MSDN: http://msdn.microsoft.com/en-us/library/bb613579.aspx.
I don't see the ItemsSource databinding on the ListBox, so I'm assuming you left it out. If you bind to something like an ObservableCollection<> then each item in the ListBox will have it's own ViewModel class. You may have public methods on those as much as you like.
If you want an event in the custom control to be handled, handle it in code-behind in the lowest level you can, in this case in the code-behind of the UserControl.
Then, in each ViewModel have an ICommand instance (or a routed command if that suits your purpose). In the UserControl you have a DataContext which you can cast to the type of your ViewModel. So the event handler can access the ViewModel and execute Commands.
Here is Josh Smith's article on Routed Commands which you might find interesting
In this article on Apps with MVVM architecture, Josh described custom ICommands
(This is pseudo-code)
class ViewModelType {
public void DoSomething() { /* ... */ }
public ICommand DoSomethingCommand { get; set; }
public string Property { get; set; }
}
class CodeBehind {
public void EventHandler(object, args) {
(DataContext as ViewModelType).DoSomethingElseCommand.Execute();
}
}
You can create an object which attaches to the CustomControl and interacts with it.
This blogpost here illustrated some useful concepts that we can expand upon: ICommand for Silverlight with Attached Behaviors
So instead of attaching to the click event of a button (which in WPF already has a command anyways) you can create a class which attaches to your custom control.
Following the pattern in the referenced blog post you would end up with:
<CustomControl
MyNamespace:CustomControlCommand.EventCommand=
"{Binding Path=CommandHandler}" />
This would give you access to the events of the CustomControl by turning them into commands.

Resources