UserControl with Exposable Command on WPF - wpf

I'm creating a Toolbar with some buttons, and I want each button to execute an different command according to the ViewModel attached to it's DataContext, so I created if like this:
public readonly DependencyProperty NewCommandProperty = DependencyProperty.Register(
"NewCommand", typeof(ICommand),
typeof(VirtueGridToolbar));
public ICommand NewCommand
{
get
{
return (ICommand)GetValue(NewCommandProperty);
}
set
{
SetValue(NewCommandProperty, value);
}
}
public GridToolbar()
{
InitializeComponent();
}
and the xaml of the control is this:
<UserControl x:Class="Virtue.Modules.Library.Controls.GridToolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ToolBar Background="Transparent">
<ToolBar.Items>
<Button x:Name="NewButton"
Width="25"
Height="25"
ToolTip="Novo"
Command="{Binding NewCommand}">
<Image Source="{DynamicResource NewLarge}" />
</Button>
<Button x:Name="EditButton"
Width="25"
Height="25"
ToolTip="Editar">
<Image Source="{DynamicResource EditLarge}" />
</Button>
<Button x:Name="DeleteButton"
Width="25"
Height="25"
ToolTip="Excluir">
<Image Source="{DynamicResource DeleteLarge}" />
</Button>
<Separator />
<Button x:Name="SaveButton"
Width="25"
Height="25"
ToolTip="Excluir">
<Image Source="{DynamicResource SaveLarge}" />
</Button>
</ToolBar.Items>
</ToolBar>
</UserControl>
But when I add the UserControl to another control and attribute the Command
<V:GridToolbar NewCommand="{Binding Path=New}" />
the command does not execute.
Any suggestions?
Tks,
Diego

Related

how to bind data when button click from view to viewmodel in wpf with Ninject Dependency Injection

i,m try to learning wpf application. i try to use ninject for DI in WPF, and work perfectly. and then, i try to create login form. in this part i have some problem, i can't bind data from view to VM when the button clicked.
this my code
LoginUserControl
<UserControl x:Class="Middleware_v2._0_with_Modern_Ui.UserControls.LoginUserControl"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:vm="clr-namespace:Middleware_v2._0_with_Modern_Ui.ViewModel"
xmlns:Custom="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
mc:Ignorable="d" DataContext="{Binding Login, Source={StaticResource Locator}}">
<Border Width="400" Height="300" BorderBrush="LightBlue" CornerRadius="5" Background="SkyBlue" Margin="0,-100,0,0">
<StackPanel Margin="0,0,10,0" Width="400">
<Label VerticalAlignment="Center" HorizontalAlignment="Center"
Content="Login Form" Margin="0,30,0,0" FontSize="20" FontWeight="Bold"/>
<Label Content="User Name" Margin="84,45,197,0"/>
<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Width="150" Height="25" Margin="165,-20,85,0"/>
<Label Content="Password" Margin="84,15,197,0"/>
<PasswordBox x:Name="txt_password" Width="150" Height="25" Margin="165,-20,85,0"/>
<Button Width="100" Height="30" Margin="-110,20,0,0" Content="Login" />
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand x:Name="btnClicked" Command="{Binding Authorize, Mode=OneTime}"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
<!--<Button Width="100" Height="30" Margin="110,-30,0,200" Content="Exit" />-->
</StackPanel>
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="15" Color="Gray" Direction="10"/>
</Border.Effect>
</Border>
LoginViewModel
public class LoginViewModel : ViewModelBase, ILoginViewModel
{
private readonly IAccountService _accountService;
public LoginViewModel(IAccountService _accountService)
{
this._accountService = _accountService;
Authorize = new RelayCommand(() => CheckAuthorized(), () => true);
}
public RelayCommand Authorize { get; set; }
private void CheckAuthorized()
{
User newUser = new User();
newUser.LoginName = _username;
newUser.LoginPassword = _password;
User user = _accountService.AuthenticationUser(newUser, 1);
throw new System.NotImplementedException();
}
}
LoginViewModel Interface
public interface ILoginViewModel
{
RelayCommand Authorize { get; set; }
}
how, to solve this? can some one help me
Simply
<Button Width="100" Height="30" Margin="-110,20,0,0" Content="Login" Command="{Binding Authorize}" />

Navigating from one screen to another in Caliburn

I am using a sample from http://www.mindscapehq.com/blog/index.php/2013/09/11/caliburn-micro-part-6-introduction-to-screens-and-conductors/
There is an AppViewModel in which other ViewModels are activated by calling ActivateItem.
The sample is working for me: I can see the corresponding View.
I now want to activate a ViewModel from another ViewModel. It gets instantiated but the corresponding View is not displayed.
How can I activate "GreenScreenViewModel" from "RedScreenViewModel"?
AppView:
<UserControl x:Class="CaliburnMicroApp_Navigation.AppView"
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">
<DockPanel Background="LightBlue" MinHeight="400" MinWidth="400">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center">
<Button x:Name="ShowRedScreen" Content="Red" Width="50" />
<Button x:Name="ShowGreenScreen" Content="Green" Width="50" Margin="12,0,0,0" />
<Button x:Name="ShowBlueScreen" Content="Blue" Width="50" Margin="12,0,0,0" />
</StackPanel>
<ContentControl x:Name="ActiveItem" />
</DockPanel>
</UserControl>
AppViewModel
public class AppViewModel : Conductor<object>
{
public void ShowRedScreen()
{
ActivateItem(new RedViewModel());
}
public void ShowGreenScreen()
{
ActivateItem(new GreenViewModel());
}
public void ShowBlueScreen()
{
ActivateItem(new BlueViewModel());
}
}
RedViewModel - this does not display GreenView ()
public class RedViewModel : Conductor<object>
{
public void DisplayGreen()
{
ActivateItem(new GrenViewModel());
}
}
RedView
<Grid Background="Red">
<StackPanel>
<TextBlock Text="red" FontSize="48" FontWeight="Bold" Foreground="#3CA527" />
<Button Name="DisplayGreen">
<TextBlock >Next Screen</TextBlock>
</Button>
</StackPanel>
</Grid>
If you want the ActiveItem displayed in the ContentControl of your AppView to change when you press your Button in RedViewModel, you will need to use the EventAggregator to pass a message from your RedViewModel to your AppViewModel.
Mindscape EventAggregator tutorial

WPF Shortcut Key not firing

I have a prism delegate command setup for refresh the data in my application.
I also have setup shortcuts for close and about window using delegate command.
Using F5 also does not trigger the refresh in the view model. If I use Alt+F4, the application closes. But it does not execute the CloseApplication method in the view model. What is missing in the following code to execute the ViewModel using the Gesture Shorcuts?
UserControl:
<UserControl.InputBindings>
<KeyBinding Gesture="ALT+F4" Command="{Binding CloseCommand}" />
<KeyBinding Gesture="F5" Command="{Binding RefreshCommand}" />
</UserControl.InputBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="E_xit" Command="{Binding CloseCommand}" InputGestureText="Alt+F4" />
<MenuItem Header="Refresh" Command="{Binding RefreshCommand}" InputGestureText="F5" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" Command="{Binding AboutCommand}" />
</MenuItem>
</Menu>
<ToolBar ToolBarTray.IsLocked="True">
<Button Content="Home" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
<Button Content="Page 1" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
<Button Content="Page 2" MinHeight="50" MinWidth="80" VerticalContentAlignment="Bottom" />
</ToolBar>
</DockPanel>
ViewModel of the UserControl
public class TopMenuViewModel:NotificationObject
{
private DelegateCommand _closeCommand;
private DelegateCommand _aboutCommand;
private DelegateCommand _refreshCommand;
public TopMenuViewModel()
{
_closeCommand = new DelegateCommand(CloseApplication);
_aboutCommand = new DelegateCommand(ShowAboutWindow);
_refreshCommand = new DelegateCommand(RefreshApplication);
}
private void ShowAboutWindow()
{
Console.WriteLine("Show about window");
}
private void CloseApplication()
{
Application.Current.Shutdown();
}
private void RefreshApplication()
{
Console.WriteLine("Refreshing..");
}
public ICommand CloseCommand
{
get { return _closeCommand; }
}
public ICommand AboutCommand
{
get { return _aboutCommand; }
}
public ICommand RefreshCommand
{
get { return _refreshCommand; }
}
}
The view model methods are called if I use the mouse to click the menu or use the Alt+x or Alt+A. But not using the KeyBinding that I have put in. Thanks for your help.

WPF & Prism 4.1 Garbage Collection / Memory Issues

I built a Prism application using WPF, .Net 4, Prism 4.1, and Unity. I'm using a DirectoryModuleCatalog to find modules at runtime. My views are displayed in a TabControl (MainRegion). When I remove a view from the region, the view and viewmodel remain in memory and never get garbage collected - the tabitem is removed. After many hours searching, I cannot figure out what I'm doing wrong.
Here's my bootstrapper:
public class Bootstrapper : UnityBootstrapper
{
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
protected override DependencyObject CreateShell()
{
var shell = new Shell();
return shell;
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog() { ModulePath = #".\Modules" };
}
}
Here's my module:
[Module(ModuleName = "ModuleA")]
public class Module : IModule
{
private IRegionManager _regionManager;
public Module(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
var view = new UserControl1();
//_regionManager.RegisterViewWithRegion("MainRegion", typeof(UserControl1));
_regionManager.Regions["MainRegion"].Add(view, "ModuleA");
_regionManager.Regions["MainRegion"].Activate(view);
}
}
And heres the viewmodel for my view that gets added to the region:
public class ViewModel
{
public DelegateCommand RemoveView { get; set; }
public ViewModel()
{
RemoveView = new DelegateCommand(() =>
{
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
var view = regionManager.Regions["MainRegion"].GetView("ModuleA");
regionManager.Regions["MainRegion"].Deactivate(view);
regionManager.Regions["MainRegion"].Remove(view);
});
}
}
And here's the code behind for the view:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
I've read that it could be because I'm instantiating the view in the module or perhaps the viewmodel in the view? When I use Red Gate Memory Profiler, and remove the view via the DelegateCommand, the view and viewmodel are both flagged as not being able to be garbage collected. Where is the reference that I'm not properly cutting?
Heres the retention graph from Ants: https://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing
Here's a test solution showing the issue.
Also, I posted the question on CodePlex as well.
It looks like you have a binding reference to it still in your retention graph.
Read and understand the following:
A memory leak may occur when you use data binding in Windows Presentation Foundation
I think it may be your problem, but you didn't show your actual bindings.
Finally found the root cause of my problem....
In our Shell.xaml we were binding IsDefault in one of our buttons to a PasswordBox's IsKeyboardFocused:
<Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
IsKeyboardFocused, is a dependency property according to MSDN - so should be good on that end.
It was related to the attached property we had on the Password box that allows us to bind to the Password entered. The focus was remaining on that password box even after we hid the ChildWindow (from WPF toolkit extended). So instead of using IsDefault, I added a keydown event to the PasswordBox and if it was Key.Enter, I would change the focused UI control and log the person into the program.
Here's the full contents of our Shell.xaml file
<Grid x:Name="MainGrid" core:SharedResourceDictionary.MergedDictionaries="TabControlThemes;MenuThemes;ButtonThemes;DataGridThemes;TreeViewThemes;ComboBoxThemes;ListBoxThemes;GroupBoxThemes;ToggleSwitchThemes">
<DockPanel>
<ContentControl x:Name="menuContent" DockPanel.Dock="Top" prism:RegionManager.RegionName="MenuRegion" />
<ContentControl DockPanel.Dock="Bottom" prism:RegionManager.RegionName="FooterRegion" />
<ContentControl DockPanel.Dock="Top" prism:RegionManager.RegionName="MainContentRegion" />
</DockPanel>
<StackPanel Orientation="Horizontal" Panel.ZIndex="4" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Visibility="{Binding IsFullScreenToggleVisible, Converter={StaticResource visConv}}" Command="{Binding ToggleFullScreen}" Height="50" Name="button4" Width="70" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
<Button.Content>
<TextBlock FontSize="12" FontWeight="Bold" TextWrapping="Wrap" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Text=" Toggle Full Screen" />
</Button.Content>
</Button>
<Button Visibility="{Binding IsAppCloseButtonVisible, Converter={StaticResource visConv}}" Command="{Binding ShutdownApplication}" Height="50" Name="button3" Width="50" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
<Button.Content>
<Image Source="..\Graphics\close.png" Name="image1" />
</Button.Content>
</Button>
</StackPanel>
<xctk:ChildWindow Name="loginChildWindow" Panel.ZIndex="3" CloseButtonVisibility="Collapsed" FocusedElement="{Binding ElementName=usernameTextBox}" WindowStartupLocation="Center" WindowState="{Binding IsVisible, Mode=TwoWay, Converter={StaticResource boolConverter}}" IsModal="True" OverlayOpacity="1" Caption="Pioneer Login" Height="164" Width="261">
<xctk:ChildWindow.OverlayBrush>
<ImageBrush Stretch="None" Viewport="0,0,46,29" ViewportUnits="Absolute" ImageSource="../Graphics/escheresque.png" TileMode="Tile" />
</xctk:ChildWindow.OverlayBrush>
<xctk:BusyIndicator IsBusy="{Binding IsLoginBusy}" BusyContent="Authenticating...">
<Grid>
<TextBox GotFocus="usernameTextBox_GotFocus" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="99,20,0,0" Name="usernameTextBox" VerticalAlignment="Top" Width="120">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding LoginCommand}" />
</TextBox.InputBindings>
</TextBox>
<Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="28,18,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="29,47,0,0" Name="label2" VerticalAlignment="Top" />
<PasswordBox attach:PasswordBoxAssistant.BindPassword="True" attach:PasswordBoxAssistant.BoundPassword="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="100,50,0,0" Name="passwordBox1" VerticalAlignment="Top" Width="120" />
<Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<Button Style="{DynamicResource RedSubmitButtonStyle}" Command="{Binding LazyLoginCommand}" Visibility="{Binding IsDebugMode, Converter={StaticResource visConv}}" Content="Quick Login" Height="23" HorizontalAlignment="Left" Margin="23,87,0,0" Name="button2" VerticalAlignment="Top" Width="89" />
</Grid>
</xctk:BusyIndicator>
</xctk:ChildWindow>
</Grid>

WPF Routed Command with Bindings per-Tab

I intended to disable and enable the Buttons outside the TabControl, just like those inside the TabItem when the current tab is changed. But the CommandBindings of the TabItem do not seem to impact "up" the visual tree. What is the right way to do this?
With this XAML:
<Window x:Class="WpfApplication10.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication10"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
<TabControl>
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand" />
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
</StackPanel>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand2"
Executed="ExecuteMyCommand"/>
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>
</Window>
With this Code Behind:
public static readonly RoutedUICommand MyCommand1 = new RoutedUICommand();
public static readonly RoutedUICommand MyCommand2 = new RoutedUICommand();
public MainWindow()
{
InitializeComponent();
}
private void ExecuteMyCommand(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Hello");
}
MSFT gave me the correct answer in their WPF forum, here (http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/bb3d1eb1-96fa-4fbc-beda-799613acb9f7)
<StackPanel>
<StackPanel FocusManager.IsFocusScope="True">
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
<TabControl>
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.CommandBindings>
<CommandBinding Command="local:Window8.MyCommand1" Executed="ExecuteMyCommand" />
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.CommandBindings>
<CommandBinding Command="local:Window8.MyCommand2" Executed="ExecuteMyCommand"/>
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>
Your don't have any code that could disable buttons. You can do it in several ways:
1. Define CanExecute event handler.
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand"
CanExecute="MyCommand_CanExecute"/>
Code behind:
private void MyCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = tabItem1.IsSelected;
}
2. Bind button IsEnabled property to tab item IsSelected property
<Button IsEnabled="{Binding ElementName=tabItem1, Path=IsSelected}"
Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
Is this all the code?
You have a special CanExecute defined, that disables the MyCommandsX ?
Or you have a binding on the Enabled Property of the bound buttons, and you implement INotifyPropertyChanged or something?
Or why should they be enabled/disabled in your code sample?
I you ask me, I wouldn't expect the code to disable the buttons..
Update 1:
You could enable the buttons the same way you did it, by adding the command bindings in the surrounding stackpanel for example.
<StackPanel>
<StackPanel.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand" />
</StackPanel.CommandBindings>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
<TabControl>
You can use the CanExecute part of the command binding to verify the conditions under which the bound buttons enabled.
Instead you should handle the command itself I think.

Resources