So I have this MenuItem which is using a list of CultureInfos as an itemsource.
What I'm trying to do is to fire a function when a CultureInfo is clicked/selected, which is supposed to change the localization of the application to the selected cultureinfo.
I can safely say that the function is working as it should.
After researching and trying a few examples, this is what I ended up with, which unfortunately doesn't work:
<MenuItem Header="{lex:LocText MenuLanguages}" ItemsSource="{Binding LanguageList}" DisplayMemberPath="Name">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Command" Value="{Binding SetLanguage}" />
<Setter Property="MenuItem.CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
The command:
private ICommand _SetLanguage;
public ICommand SetLanguage
{
get
{
if (_SetLanguage == null)
_SetLanguage = new RelayCommand(ChangeLanguage);
return _SetLanguage;
}
}
public void ChangeLanguage(object langChosen)
{
LocalizeDictionary.Instance.Culture = CultureInfo.GetCultureInfo(langChosen.ToString());
}
CultureInfo.GetCultureInfo() takes string as a parameter.
The itemsource is basically an ObservableCollection<CultureInfo>.
My question is what could be wrong with the above code? I have been trying quite a few 'solutions' but nothing really worked...
When I select an item form the list nothing happens at all.
*I also tried to set a breakpoint on the ChangeLanguage method, which brought me to a conclusion that the method never even fires.
Using caliburn.micro and WPFLocalizationExtension extension.
If it doesn't work, then the binding is wrong. Check out for binding errors in debug window.
You need to use relativesource, since binding directly wont do what you think will do.
<MenuItem Header="_Recent files" ItemsSource="{Binding RecentFiles, Converter={StaticResource RecentFilesToListOfStringsConverter}, Mode=OneWay}" >
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding DataContext.ImportRecentItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type MenuItem}, AncestorLevel=1}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
A Menu has a different LogicalTree than the rest of the Markup. For this Reason you need to search for the right DataContext first as Erti-Chris suggested.
Also every DataTemplate has the DataContext of the Type T which is part of the List of the bound ItemsSource.
Related
I'm working on a WPF application that is using styles and templates to dynamically build a ribbon menu, here are the relevant snippets:
<RibbonTab x:Name="HomeTab" Header="Home" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource GroupStyle}" ItemsSource="{Binding Groups}"/>
<Style TargetType="RibbonGroup" x:Key="GroupStyle">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="ItemsSource" Value="{Binding Controls}"/>
<Setter Property="ItemTemplate" Value="{StaticResource RibbonButtonTemplate}"/>
</Style>
<DataTemplate x:Key="RibbonButtonTemplate" DataType="{x:Type enums:RibbonControlConfig}">
<RibbonButton Label="{Binding Header}" LargeImageSource="{Binding Image}" Command="{Binding Command}"/>
</DataTemplate>
So now Resharper is complaining about the bindings within the GroupStyle since they are actually elements of a child property of the view model, as can be seen by the ItemSource binding on the RibbonTab.
This does of course function just fine, I would just prefer to have both no complaints from ReSharper and access to accurate Intellisense, so is there anyway to tell the style what it's context is?
Side note: I did first try to do this setup by using nested data templates but I wasn't able to get anything passed the first level template to work.
No, it's not possible to specify the DataContext type in a style. In general, you shouldn't use bindings in a style anyway, because a style is about appearance, not about data. It's especially important to follow this rule if you plan to make your control reusable: you can't make assumptions about what it will be bound to.
i want to write a WPF-Application that shows different pages/scenes. So, I have a ViewModel (MainViewModel) that provides a list of scenes (SceneViewModel). Every scene has a name which can be accessed by a property SceneName.
I create the MainViewModel in Window.DataContext:
<Window.DataContext>
<!-- Declaratively create an instance of the main model -->
<models:MainViewModel />
</Window.DataContext>
I then want a menu-item that lists all scenes. When one of the menu-items is clicked, the scene should change. Therefor i created an Command in the MainViewMode: ChangeSceneCommand.
In XAML I want to create the menu-list in the following way:
<Menu Grid.Row="0">
<Menu.Resources>
<Style x:Key="SetSceneCommandItem" TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding SceneName}"/>
<Setter Property="Command" Value="{Binding SetSceneCommand}"/> <-- Here is the problem
<Setter Property="IsChecked" Value="False" />
</Style>
</Menu.Resources>
<MenuItem Header="Scenes" ItemsSource="{Binding Scenes}" <-- Scenes is a list with scenes^^
ItemContainerStyle="{StaticResource SetSceneCommandItem}" /> <-- Here the style is set
</Menu>
The Item-Header binds well but the "SetSceneCommand" can not be found, because wpf tries to find the "SetSceneCommand"-property in the SceneViewModel. How can i say wpf to access the model in the datacontext out of the style?
PS: You may have noticed that SetSceneCommand will need a scene as parameter to work, but I wanted to implement that later.
You can use RelativeSource. If SetSceneCommand is part of the same context used by Menu then it will look like this:
<Setter
Property="Command"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type Menu}}, Path=DataContext.SetSceneCommand}"/>
this tells Binding to go up the visual tree until Menu and take DataContext.SetSceneCommand from there
I'm making a MVVM WPF application, in this application I have a ListBox with my own Privilege Items.
After ages I finally found a solution how to get selection synchronized with my ViewModel. (You also need to implement IEquatable in your item class)
Problem
Now i want to style the ListBoxItems as CheckBoxes, there are many solutions for this problem, but none that really fits my needs.
So i came up with this solution, because I can apply this style only to the ListBoxes I need, and I don't have to worry about the DisplayMemberPath or that the Items were styled as CheckBox and ListBoxItems.
View:
<ListBox Grid.Row="5" Grid.Column="1"
ItemsSource="{Binding Privileges}"
BehavExt:SelectedItems.Items="{Binding SelectedPrivileges}"
SelectionMode="Multiple"
DisplayMemberPath="Name"
Style="{StaticResource CheckBoxListBox}"/>
Style:
<Style x:Key="CheckBoxListBox"
TargetType="{x:Type ListBox}"
BasedOn="{StaticResource MetroListBox}">
<Setter Property="Margin" Value="5" />
<Setter Property="ItemContainerStyle"
Value="{DynamicResource CheckBoxListBoxItem}" />
</Style>
<Style x:Key="CheckBoxListBoxItem"
TargetType="{x:Type ListBoxItem}"
BasedOn="{StaticResource MetroListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox IsChecked="{TemplateBinding Property=IsSelected}">
<ContentPresenter />
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ViewModel:
private ObservableCollection<Privilege> _privileges;
public ObservableCollection<Privilege> Privileges
{
get { return _privileges; }
set {
_privileges = value;
RaisePropertyChanged(() => Privileges);
}
}
private ObservableCollection<Privilege> _selectedPrivileges;
public ObservableCollection<Privilege> SelectedPrivileges
{
get { return _selectedPrivileges; }
set
{
_selectedPrivileges = value;
RaisePropertyChanged(() => SelectedPrivileges);
}
}
The Problem is this line:
IsChecked="{TemplateBinding Property=IsSelected}"
It works fine, but only in one direction. When add a item to my SelectedPrivileges in the code it will be displayed as checked, but when I check this item in the GUI it won't do anything. (Without the CheckBox style it works, so it is because a TemplateBinding only works in one direction)
How do I get this to work? I though about something like a trigger, but I have no clue how to accomplish this.
I believe what you're looking for is actually pretty straightforward. You need to change the binding mode of the IsChecked property's binding, as follows:
{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay}
That should do it.
This and basically any other WPF binding tips can be found on this excellent cheat sheet.
I have a ListView with an ItemSource from a List of string.
Now I have added a context menu which should just implement some commands. But the problem ist how to set the DataContext. Found some solutions but none of these worked for me. Dont know where my fault ist.
Here my XAML code, reduced to the important regions.
<ListView x:Name="lstBackups" ItemsSource="{Binding SelectedClient.Backups}">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Do Something" DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}}"
cinch:SingleEventCommand.RoutedEventName="MouseLeftButtonUp"
cinch:SingleEventCommand.TheCommandToRun="{Binding Path=DataContext.OpenBackupInExplorerCommand, ElementName=UserControl}">
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I'm sure you've noticed that the ContextMenu is not part of the same visual tree as your user control (annoying I know). So you have to get a bit creative with your binding logic.
Try changing the command binding to the following
cinch:SingleEventCommand.TheCommandToRun="{BindingPath=PlacementTarget.DataContext.OpenBackupInExplorerCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}}"
That should attempt to get the DataContext of the placement target (in your case the ListView) which should inherit the DataContext of the UserControl
Hopefully that will work.
I try to use a context menu from a user control's list view but the command is not firing (neither enabling/disabling when needed).
Code:
<UserControl ....
<UserControl.Resources>
<ContextMenu x:Key="SharedInstanceContextMenu">
<MenuItem Header="Edit" Command="{Binding ElementName=UC, Path=DataContext.EditSelectedItemCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
<Grid ...>
<ListView ....>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
<Setter Property="ContextMenu" Value="{StaticResource SharedInstanceContextMenu}"/>
</Style>
</ListView.ItemContainerStyle>
How can I make the command firing (and enabling/disabling, part of the command behavior)?
(btw, this questions seems similar to Treeview context menu command not firing but after trying all solutions there it still does not work.)
Does your output window contain binding errors complaining the command doesn't exist on your view model? If so, it probably means that your ContextMenu's DataContext isn't set correctly. Context menus are not part of the visual tree because they need to pop up on top of elements which means they don't inherit their DataContext the way other controls do. One solution is to use the PlacementTarget to access your view model - see this post for more information.