I have an application that has a Navigation Menu that uses Commands to go from page to page.
The Navigation Menu has been created in Xaml and i have it stored in Navigation.xaml see below
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Cirdan.Wpf.Navigation"
xmlns:infrastructure="clr-namespace:Cirdan.Wpf.Infrastructure">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Cirdan.Wpf;component/Resources/Styles/Stylesheet.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="Navigation" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<UniformGrid Grid.Row="0" Columns="1">
<Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type vm:NavigationViewModelBase}}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding ViewerPageCmd}" >Viewer Screen</Button>
<Button DataContext="{Binding NavigationViewModel, Source={x:Static infrastructure:MainWindow.LocatorX}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding}" >Acquisition Screen</Button>
<Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type vm:NavigationViewModelBase}}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding WorklistPageCmd}" >Worklist Screen</Button>
</UniformGrid>
<ToggleButton Grid.Row="1" Style="{StaticResource ToggleBtnToolStyle}" x:Name="Menu" IsChecked="true" Background="Transparent" BorderThickness="0" >
<StackPanel Orientation="Horizontal">
<ContentPresenter Margin="5" Height="50" Content="{StaticResource MenuIcon}"></ContentPresenter>
<Viewbox>
<TextBlock Margin="5" Style="{StaticResource TxtToolStyle}">Menu</TextBlock>
</Viewbox>
</StackPanel>
</ToggleButton>
</Grid>
</DataTemplate>
The ViewModel that I am trying to Bind these Button Commands to is called NavigationViewModelBase.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
namespace Cirdan.Wpf.Navigation
{
public abstract class NavigationViewModelBase : ViewModelBase
{
private List<DicomMetadataModel> _dicomMetadata;
//Navigation Cmd
public ICommand AcquisitionPageCmd { get; private set; }
public ICommand ManualEntryWindowCmd { get; private set; }
public ICommand SessionWindowCmd { get; private set; }
public ICommand SettingsWindowCmd { get; private set; }
public ICommand StudyInfoPageCommandCmd { get; private set; }
public ICommand ViewerPageCmd { get; private set; }
public ICommand WorklistPageCmd { get; private set; }
protected NavigationViewModelBase()
{
AcquisitionPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.AcquisitionScreen)));
ManualEntryWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.ManualEntry, DicomMetadata)));
SessionWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.Session)));
SettingsWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.Settings)));
ViewerPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.Viewer)));
WorklistPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.Worklist)));
}
}
}
On each page i then use the following code to add the Navigation
<ContentControl Grid.Column="2" Grid.Row="2" ContentTemplate="{StaticResource Navigation }" />
At the moment I'm not getting any errors, and when I have set the DataContext in one of my buttons above, when I go to bind my commands i can see all the properties of that Viewmodel so that bit is working correctly, However when i run the program and click on these buttons nothing is happening.
Thanks for any help
Ancestor Binding will only work for element in visualtree/view or simply elemnts in your page. A viewModel is not anywhere in the page as a control. So in place of viewModel give the type of view which has NavigationViewModelBase as datacontext.write binding As below (if your view/control is NavigationView the binding will be). and in path write the property of vm:NavigationViewModelBase
class :
<Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:NavigationView}}, path= PropertyYouWantToBind}"
just make sure if you have not defined DataContext for any other control in hierarchy, Button will be getting same DataContext as view, then you just have to bind the command. which you have already done correctly.
if you have not given the DataContext to any control in your view then just give that to you contentControl or Grid. simply as
<Grid>
<Grid.DataContext>
<vm:NavigationViewModelBase />
</Grid.DataContext>
<Grid.RowDef.......
and then use simple binding for command.
RelativeSource FindAncestor looks for ancestors in VisualTree.
VisualTree can look like:
Window
Grid
TextBlock
TextBox
Button
ViewModels are not in visual three
For example ancestors of Button are Grid and Window in this case.
How to do it then?
well, create custom UserControl instead ContentControl with ContentTemplate in ResourceDictionary.
In the usercontrol set DataContext to the class that inherits from NavigationViewModelBase.
then the binding will be simple:
<UniformGrid Grid.Row="0" Columns="1">
<Button Command="{Binding ViewerPageCmd}">Viewer Screen</Button>
<Button Command="{Binding AcquisitionPageCmd}">Acquisition Screen</Button>
<Button Command="{Binding WorklistPageCmd}" >Worklist Screen</Button>
</UniformGrid>
Related
I'm currently in the process of implementing a menu navigation system for a group project. We're using Caliburn.Micro and the MVVM pattern.
The menu is located in the ShellView.xaml and is based on a List<NavigationMenuItem> that has been filtered using the Role property.
public class NavigationMenuItem
{
public IScreen ViewModel { get; set; }
public string IconPath { get; set; }
public string Role { get; set; }
public NavigationMenuItem(IScreen viewModel, string iconPath, string role)
{
ViewModel = viewModel;
IconPath = iconPath;
Role = role;
}
}
The menu is displaying just fine, but now I want to pass the ViewModel-property to a method in the ShellViewModel.cs, such that I can activate a view change. This is how the ShellView.xaml looks so far:
<Window
x:Class="P3GG.Views.ShellView"
xmlns:cal="http://www.caliburnproject.org"
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:local="clr-namespace:P3GG.Views"
xmlns:models="clr-namespace:P3GG.Models"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:templates="clr-namespace:P3GG.Templates"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="Title"
Width="800"
Height="600"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Visibility="{Binding SidebarIsVisible, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"
Grid.Column="0"
Background="#333333"
x:Name="NavigationMenu">
<ListBox.ItemTemplate>
<DataTemplate DataType="models:NavigationMenuItem">
<Button cal:Message.Attach="Handle( <!-- pass content of NavigationMenuItem.ViewModel --> )" Style="{StaticResource BtnSidebar}">
<Image Margin="20" Source="{Binding IconPath}"/>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl Grid.Column="1" x:Name="ActiveItem"/>
</Grid>
</Window>
The ShellViewModel.cs currently contains two Handle methods:
public void Handle(Screen screen)
public void Handle(User user)
How do I pass the ViewModel property of a given NavigationMenu to the Handle(Screen) method?
EDIT
Added Handle method per request
public void Handle(Screen screen)
{
if (screen is LoginViewModel)
{
SidebarIsVisible = false;
NotifyOfPropertyChange(() => SidebarIsVisible);
}
else
{
SidebarIsVisible = true;
NotifyOfPropertyChange(() => SidebarIsVisible);
}
ActivateItem(screen);
}
Maybe you can try something like this, as explained here:
<Button cal:Message.Attach="[Event Click] = [Action Handle($dataContext)]" Style="{StaticResource BtnSidebar}">
<Image Margin="20" Source="{Binding IconPath}"/>
</Button>
This will pass the full view model (DataContext) to your handler.
To pass a specific property of your view model, use the long syntax as indicated here:
<Button Style="{StaticResource BtnSidebar}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="Handle">
<cal:Parameter Value="{Binding ViewModel}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Margin="20" Source="{Binding IconPath}"/>
</Button>
with i defined as
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
You could also change the DataContext property of the Button to the property of interest, like:
<Button DataContext="{Binding ViewModel}" cal:Message.Attach="[Event Click] = [Action Handle($dataContext)]" Style="{StaticResource BtnSidebar}">
<Image Margin="20" Source="{Binding IconPath}"/>
</Button>
so only the correct property gets passed to your hendler, but this feels like a hack.
On click, this will hand-over the DataContext of the Button as parameter of your Handle method, which should be a NavigationMenuItem.
I'm working with WPF with Prism (MVVM), and trying to build an Inspector for a few classes. One of those classes is Vector3:
<Grid x:Name="Vector3Root" Background="White">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="X" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding X}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="Y" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding Y}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="Z" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding Z}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
</StackPanel>
</Grid>
And its code-behind
namespace SimROV.WPF.Views{
public partial class Vector3View : UserControl
{
public Vector3View()
{
InitializeComponent();
}
public static readonly RoutedEvent SettingConfirmedEvent =
EventManager.RegisterRoutedEvent("SettingConfirmed", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(Vector3View));
public event RoutedEventHandler SettingConfirmed
{
add { AddHandler(SettingConfirmedEvent, value); }
remove { RemoveHandler(SettingConfirmedEvent, value); }
}
public void Vector3ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
RaiseEvent(new RoutedEventArgs(SettingConfirmedEvent));
}
}}
The problem that I'm struggling with is that I can't catch neither of the fired events (ValueChanged or SettingConfirmed) on another UserControl's ViewModel that is using Vector3View:
<UserControl
x:Class="SimROV.WPF.Views.TransformView"
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:views="clr-namespace:SimROV.WPF.Views"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:prism="http://prismlibrary.com/"
mc:Ignorable="d" >
<Grid x:Name="TransformRoot" Background="White">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Position" Margin="5"/>
<!--<ContentPresenter ContentTemplate="{StaticResource Vector3Template}"/>-->
<views:Vector3View x:Name="PositionVector3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SettingConfirmed">
<prism:InvokeCommandAction Command="{Binding PositionValueChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</views:Vector3View>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Rotation" Margin="5"/>
<!--<ContentPresenter ContentTemplate="{StaticResource Vector3Template}"/>-->
<views:Vector3View x:Name="RotationVector3" SettingConfirmed="RotationValueChangedEvent"/>
</StackPanel>
</StackPanel>
</Grid>
At this point I CAN catch SettingConfirmed with RotationValueChangedEvent on code-behind, but since I'm following MVVM pattern, that doesn't work for me, which is why I'm using EventTrigger and InvokeCommandAction to catch those events on TransformViewModel, but those never get fired.
Here it's the TransformViewModel:
namespace SimROV.WPF.ViewModels{
public class TransformViewModel : BindableBase
{
private ICommand _positionCommand;
public ICommand PositionValueChangedCommand => this._positionCommand ?? (this._positionCommand = new DelegateCommand(PositionChanged));
private void PositionChanged()
{
}
public TransformViewModel()
{
}
}}
PositionChanged just never gets fired and I can't understand why at all.
I don't know if this is relevant, but Transform is an element of an ObservableCollection<IComponent> at another ViewModel, which is being presented by a ListView with a ItemContainerStyle, that has a ContentPresenter with a ContentTemplateSelector inside.
Can someone point me out on why this is happening and how to fix it?
Thank you.
Your EventTrigger and InvokeCommandAction should work just fine provided that the DataContext of the Vector3View actually is a TransformViewModel so the binding to the PositionValueChangedCommand property succeeds.
I'm using Prism RegionManager, to register different views with a TabControl region inside the MainView.
MainView.xaml
<TabControl regions:RegionManager.RegionName="MainViewTabRegion">
<TabControl.ItemTemplate>
<DataTemplate>
<DockPanel Width="Auto">
<Button Command="{Binding DataContext.DataContext.CloseTabCommand, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
FontFamily="Courier"
FontWeight="Bold"
Margin="4,0,0,0"
FontSize="10"
VerticalContentAlignment="Center"
Width="15" Height="15" />
<ContentPresenter Content="{Binding DataContext.DataContext.HeaderText, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" />
</DockPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
In MainViewViewModel I'm Adding different views with the same base class.
MainViewViewModel.cs:
private void AddProjectView() {
var view = _container.Resolve<ProjectSettingsView>();
var dataContext = _container.Resolve<ProjectSettingsViewModel>();
dataContext.HeaderText = "test header txt";
view.DataContext = dataContext;
_regionManager.RegisterViewWithRegion("MainViewTabRegion", () => view);
}
I can add new tab item with the view.
How can I close the tab item, the <TabControl.ItemTemplate> in the XAML code above, adds a close button with CloseCommand in the ProjectSettingsViewModel, with the TabItem bonded to it.
ProjectSettingsViewModel.cs
private void OnExecuteCloseCommand(object tabItem) {
//Close this TabItem
}
Bind the CommandParameter property of the Button to the DataContext of the TabItem:
<Button Command="{Binding DataContext.DataContext.CloseTabCommand, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
FontFamily="Courier"
FontWeight="Bold"
Margin="4,0,0,0"
FontSize="10"
VerticalContentAlignment="Center"
Width="15" Height="15" />
You could then remove the view like this in the view model:
public class ProjectSettingsViewModel
{
private readonly IRegionManager _regionManager;
public ProjectSettingsViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
CloseTabCommand = new DelegateCommand<object>(OnExecuteCloseCommand);
}
private void OnExecuteCloseCommand(object tabItem)
{
_regionManager.Regions["MainViewTabRegion"].Remove(tabItem);
}
public DelegateCommand<object> CloseTabCommand { get; }
}
You just need to get the reference to your IRegionManager. Then you get the Region that your view belongs to, and call Remove on the region and pass the tabItem reference to remove it.
Ex:
private void OnExecuteCloseCommand(object tabItem) {
regionManager.Regions["MainViewTabRegion"].Remove(tabItem);
}
You can actually just place this in your MainViewViewModel and bind to it in the DataTemplate, then you don't have to rewrite the close command for each tab item's view model.
I cover this in my Pluralsight course "Prism Problems & Solutions: Mastering the Tab Control". You can see the solution here: https://app.pluralsight.com/library/courses/prism-mastering-tabcontrol/table-of-contents
Essentially, you just need to create a TriggerAction that does all the work for you. Simple. Nothing is needed in the VM.
Let me begin with apologizing for the perhaps somewhat vague title, I'm having a hard time explaining my problem! Perhaps this is why I'm hardly getting any Google results, with this post being the closest to my problem (I think): How to bind to a property of the ViewModel from within a GridView
Anyways, I have a list of news articles that are being dynamically generated. The user has the option to press a "Star"-button in order to add an article to his/her favorites list. This "Star"-button should thus only be visible when the user is logged in.
I'm trying to achieve this by setting the Visibility of the Button to a property called IsLoggedIn inside my ViewModel. However, because this is happening inside my ListView it's trying to find the property IsLoggedIn inside of Article instead of the ViewModel.
So I guess my questions boils down to: How can I bind to a ViewModel property inside of a Databound ListView?
<ListView ItemsSource="{x:Bind VM.Articles, Mode=OneWay}" ItemClick="DebuggableListView_ItemClick" IsItemClickEnabled="True" SelectionMode="None" Grid.Row="1" VerticalAlignment="Top">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Article">
<Grid Margin="0,10,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding Image}" Margin="0,0,10,0" Grid.Column="0" VerticalAlignment="Top" ImageFailed="Image_ImageFailed"/>
<Button Visibility="{x:Bind VM.IsLoggedIn, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}" FontFamily="Segoe MDL2 Assets" Content="" FontSize="30" Background="Transparent" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<StackPanel Grid.Column="1">
<TextBlock TextWrapping="Wrap" FontWeight="Bold" Text="{Binding Title}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Summary}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Requested Article class:
public sealed class Article
{
public int Id { get; set; }
public int Feed { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public DateTime PublishDate { get; set; }
public string Image { get; set; }
public string Url { get; set; }
public string[] Related { get; set; }
public Category[] Categories { get; set; }
public bool IsLiked { get; set; }
}
Okay, so currently I got it working by having a property which gets the singleton of my VM, however I'm sure there has to be a cleaner way to get something simple like this working. I've added a sample rar (OneDrive link: https://1drv.ms/u/s!Ar4fOTiwmGYnyWbwRY6rM0eFsL9x) which has a list, a ViewModel, some dummy data and a Visibility property inside the VM. If you can get it working without my dirty method please feel free to commit as an answer.
This type problem can best be solved using relative binding. Rather than binding directly to the current DataContext, i.e. this case the individual item in the ListView's ItemsSource, you can bind to a property of any ancestor element.
Given a simple ViewModel class
public class ViewModel: ViewModelBase
{
private bool _isLoggedIn;
public bool IsLoggedIn
{
get { return _isLoggedIn; }
set
{
_isLoggedIn = value;
RaisePropertyChanged(() => IsLoggedIn);
}
}
public IEnumerable<string> Items
{ get { return new[] {"One", "Two", "Theee", "Four", "Five"}; } }
}
the View can then be defined as
<Window x:Class="ParentBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ParentBindingTest"
Title="MainWindow"
Width="300" Height="400">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox Margin="16,8" HorizontalAlignment="Left" Content="Logged In?" IsChecked="{Binding IsLoggedIn, Mode=TwoWay}" />
<ListView Grid.Row="1" Margin="16,8" ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Visibility="{Binding Path=DataContext.IsLoggedIn, RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Converter={StaticResource BooleanToVisibilityConverter}}">
<Image Source="Images\remove.png" />
</Button>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Note how in the item DataTemplate, the TextBlock's Text property is bound directly to the item.
However the Button's Visibility is bound not to a propery of it's own DataContext, but to that of the ListView itself, using relative binding.
I am creating custom control for menu and I have ListBox in my control. Something like this:
<ListBox x:Name="MenuItemsList"
Grid.Row="1"
ItemsSource="{Binding ProgramList, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when I want to catch Tap event, get properties from class and keep MVVM model. How can I catch this in MainPage.xaml.cs or in MainViewModel?
I have this code in my MainPage.xaml:
<controls:BottomMenu x:Name="BottomMenu" Canvas.Top="{Binding MenuCanvasTop}"
Width="480" Height="400">
</controls:BottomMenu>
I have prepare this code in my MainViewModel:
public RelayCommand<string> GoToSectionCommand
{
get
{
return goToArticleCommand
?? (goToArticleCommand = new RelayCommand<string>(
NavigateToSection));
}
}
But I don't know how can I call it. What's the best way?
Edit:
I tried to extend listbox:
<ListBox x:Name="MenuItemsList"
Grid.Row="1"
ItemsSource="{Binding ProgramList, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Button Content="{Binding Title}"
Command="{Binding ListButtonClickCommand, Source={RelativeSource Self}}"
CommandParameter="{Binding Url}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With code-behind:
public ICommand ListButtonClickCommand
{
get { return (ICommand)GetValue(ListButtonClickCommandProperty); }
set { SetValue(ListButtonClickCommandProperty, value); }
}
public static readonly DependencyProperty ListButtonClickCommandProperty =
DependencyProperty.Register("ListButtonClickCommand", typeof(ICommand), typeof(BottomMenu), new PropertyMetadata(null));
public BottomMenu()
{
InitializeComponent();
}
Then in MainPage.xaml:
<controls:BottomMenu x:Name="BottomMenu" Canvas.Top="{Binding MenuCanvasTop}"
Width="480" Height="400"
ListButtonClickCommand="{Binding MenuItemButtonCommand}">
</controls:BottomMenu>
And in MainViewModel:
private ICommand menuItemButtonCommand;
public ICommand MenuItemButtonCommand
{
get
{
return menuItemButtonCommand
?? (menuItemButtonCommand = new RelayCommand(
NavigateToArticleSection));
}
}
For now without luck. It's not working. RelayCommand isn't triggered.
Edit2
I guess the problem is with binding command in custom control but I don't know how to fix it.
You just need to bind to the UserControl -- using "RelativeSource Self" will bind to the Button, which is not what you want. You should be able to use an "ElementName" binding to locate the user control:
<UserControl x:Name="UserControlName" ... >
...
<Button Content="{Binding Title}"
Command="{Binding ElementName=UserControlName,Path=ListButtonClickCommand}"
CommandParameter="{Binding Url}"/>
...
</UserControl>