I wrote a few key binding commands for my app,
<KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding Check, Mode=OneWay}"/>
This command should should turn on/off IsEnable property for one of the menu items and check/uncheck the other menu item,
<MenuItem
Name="Message_menu_item"
InputGestureText="Ctrl+M"
Header="_Message"
IsEnabled="{Binding IsMessageMenuEnabled}"/>
<MenuItem
Name="Check_menu_item"
InputGestureText="Ctrl+C"
Command="{Binding Check, Mode=OneWay}"
Header="Check"
IsCheckable="True"
IsChecked="false"/>
It works ok, by clicking the item itself, but it doesn't work at all when the menu is closed, or when the menu is open, it only changing the IsEnable without checking/unchecking the property.
My viewModel properties:
public bool IsMessageMenuEnabled => this.IsChecked;
public bool IsChecked
{
get => this.isChecked;
set
{
this.isChecked = value;
this.OnPropertyChanged();
this.OnPropertyChanged(nameof(this.IsMessageMenuEnabled));
}
}
And my constructor with Check command
public MainViewModel()
{
Check = new RelayCommand(o =>
{
if (IsChecked == false)
{
IsChecked = true;
}
else
{
IsChecked = false;
}
});
}
I want to trigger it by clicking ctrl+c even if the menu is closed, but it doens't work, please help.
Related
Here I have added a boolean property in model and binding it to Isenabled property of Combobox . And Binding Command to button in which I have added execute() method which sets the property binded to combobox. However this changes isEnable of Button. Is there a way to disable combobox on btn click?
Model:
public class MyPanelModel : BindableBase
{
private bool _MessageVisibilty;
public bool MessageVisibilty
{
get
{
return _MessageVisibilty;
}
set
{
SetProperty(ref _MessageVisibilty, value);
}
}
}
View Model:
private MyPanelModel plModel;
public MyPanelModel MyPnlModel
{
get { return plModel; }
set { SetProperty(ref plModel,value); }
}
private readonly DelegateCommand _hideCommand;
public DelegateCommand DisableOtherControlsCommand
{
get { return _hideCommand; }
}
public MyPanelViewModel()
{
_hideCommand = new DelegateCommand(hideExecute, canExecute);
_hideCommand.RaiseCanExecuteChanged();
}
private void hideExecute()
{
MyPnlModel.MessageVisibilty = false;
}
private bool canExecute()
{
return true;
}
Xaml :
<ComboBox Mandatory="True">
<i:Interaction.Triggers >
<i:EventTrigger EventName="IsEnabled">
<prism:InvokeCommandAction Command="{Binding MyPanelModel.MessageVisibilty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Button Margin="10" Command="{Binding MyPanelViewModel.DisableOtherControlsCommand}" >Save</Button>
If you want to use MVVM the idea is to bind the IsEnable property of your button to a boolean in your viewmodel.
If your viewmodel implements INotifyPropertyChanged and is set as a datacontext for your view, when you will update the boolean value in your viewmodel, the control which is bind to the boolean property should be enable/disabled
If you wand to change the boolean after a click on the button you can simply create a Command and bind your button Command property on it. In your command method implementation, set the boolean value to true/false it will reflect on the ui's isenable property immediately
For Command creation, here is another topic that may help you :
How to bind WPF button to a command in ViewModelBase?
What I am trying to accomplish is to have a combo box that in a row on the DataGrid. Each of the comboboxes are bound to the same ItemsSource. I would like to have the end user be able to click on an item in the combobox and for that specific combobox, have that item be the selected item. And the rest of the comboboxes will then hide the selected value. I am still new to XAML though I do understand the whole MVVM pattern (which is what I am using).
XAML:
<DataGridTemplateColumn Header="Database Column" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.DatabaseMappingFields, ElementName=Root}" DisplayMemberPath="ColumnName">
<ComboBox.Resources>
<Style TargetType="ComboBoxItem">
<Setter Property="Visibility" Value="{Binding IsSelected, Converter={StaticResource InverseBoolToVis}}"/>
</Style>
</ComboBox.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<command:EventToCommand Command="{Binding DataContext.CommandDatabaseHeaderSelected, ElementName=Root}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
C#:
SetDatabaseColumns(new List<string>()
{ "Item1", "Item2", "Item3", "Item4", "Item5", "Item6" });
public void SetDatabaseColumns(List<string> databaseColumnNames)
{
DatabaseMappingFields.Clear();
DatabaseMappingFields.Add(new DatabaseColumnsModel() { ColumnName = "<ignore>" });
foreach (var item in databaseColumnNames)
{
DatabaseMappingFields.Add(new DatabaseColumnsModel() { ColumnName = item });
}
}
public ICommand CommandDatabaseHeaderSelected
{
get
{
return _commandDatabaseHeaderSelected ??
(_commandDatabaseHeaderSelected = new RelayCommand<SelectionChangedEventArgs>(DatabaseHeaderSelected));
}
}
private void DatabaseHeaderSelected(SelectionChangedEventArgs args)
{
var selectedItem = args.AddedItems.Count >= 1
? args.AddedItems[0] as DatabaseColumnsModel
: null;
var previousItem = args.RemovedItems.Count >= 1
? args.RemovedItems[0] as DatabaseColumnsModel
: null;
var selectedFileMapping = Data.TextFileMapping.FirstOrDefault(w => w == SelectedFileMapping);
if (selectedItem == null) return;
var isSelected = IsSelectedItemEnabled(selectedItem, previousItem);
selectedItem.IsSelected = isSelected;
selectedFileMapping.DatabaseColumn = isSelected ? selectedItem : null;
if (previousItem == null) return;
previousItem.IsSelected = false;
}
public class DatabaseColumnsModel : ObservableObject
{
private string _columnName;
private bool _isSelected;
private int _index;
public int Index
{
get { return _index; }
set { Set(() => Index, ref _index, value); }
}
public string ColumnName
{
get { return _columnName; }
set { Set(() => ColumnName, ref _columnName, value); }
}
public bool IsSelected
{
get { return _isSelected; }
set { Set(() => IsSelected, ref _isSelected, value); }
}
}
Since we are making a desktop app and would like to have a common look and feel around all of our apps, we have decided to use WPF and CefSharp and use WPF as a shell and the front end will be HTML based and use a WPF CefSharp control to display a browser window inside of WPF.
I'm developing a WPF project from MVVM way.
I bound Observable Collection to a XamTabControl. And if I add a new item to the Observable Collection a new tab is generated. But if I close the tab, the tab item is not removed from the Observable Collection.
I can do this manually if i can trigger the Closing Event (or Closed Event) for the tab. But those two events are not fired. But some event are fired such as MouseUp.
<igWindows:XamTabControl
Height="198"
HorizontalAlignment="Left"
Margin="0,54,0,0"
ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTab}"
Name="xamTabControl1"
VerticalAlignment="Top"
Width="651">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding TabCloseCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<igWindows:XamTabControl.ItemContainerStyle>
<Style TargetType="igWindows:TabItemEx">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="CloseButtonVisibility" Value="{Binding CloseButtonVisibility}"/>
</Style>
</igWindows:XamTabControl.ItemContainerStyle>
<igWindows:XamTabControl.ContentTemplate>
<!-- this is the body of the TabItem template-->
<DataTemplate>
<TextBlock Text="{Binding Content}" />
</DataTemplate>
</igWindows:XamTabControl.ContentTemplate>
</igWindows:XamTabControl>
And this is my View Model
private ObservableCollection<TabItem> tabs;
private TabItem selectedTab;
private ICommand tabCloseCommand;
public ObservableCollection<TabItem> Tabs
{
get
{
return tabs;
}
set
{
tabs = value;
NotifyPropertyChanged("Tabs");
}
}
public TabItem SelectedTab
{
get
{
return selectedTab;
}
set
{
selectedTab = value;
NotifyPropertyChanged("SelectedTab");
}
}
public ICommand TabCloseCommand
{
get
{
if (tabCloseCommand == null)
{
tabCloseCommand = new RelayCommand(param => this.CloseTab(), null);
}
return tabCloseCommand;
}
}
private void CloseTab()
{
}
It's probably because the DataContext for the object that runs the Closing event is your TabItem class, and not the class that contains the TabCloseCommand
Use ElementName or RelativeSource to set the Source of your command binding to the TabControl.DataContext first, and it should work
<i:InvokeCommandAction Command="{Binding ElementName=xamTabControl1,
Path=DataContext.TabCloseCommand}" />
The code that you have to wire up the closing event doesn't work because there is no Closing or Closed event on the XamTabControl and that is the associated object. I am not sure if it is possible to use the EventTrigger to attach to an event of the TabItemEx from the xamTabControl. If you were to add a handler to the XamTabControl without the EventTrigger, you would do the following:
<igWindows:XamTabControl
Name="xamTabControl1"
AllowTabClosing="True"
igWindows:TabItemEx.Closed="OnTabClosed">
</igWindows:XamTabControl>
You can also see a detailed example in the Removing a Closed Tab topic in the help.
I am new to MVVM, and also fairly new to WPF. As a matter of fact I started programming just a few months ago. MVVM is really dng my head in with the binding concept, and I have been trying for days now to just simply make an application that allows you to select an item from a listbx, and when you click on the add button the selected item should be saved in a new list. The second listbox displays the latest items added, and you can select an item and delete it by using another button. ususally I would go for the click event and decorate my codebehind with pretty little methods, but I really want to learn how to do all this by using bindings and no codebehind.
I would be extremly happy for any help, and please remember that I am new to this and I really want to keep it as simple as possible :)
with kind regards Daniela
<WrapPanel HorizontalAlignment="Center" Margin=" 10">
<ListBox x:Name="Firstbox"
Width="100"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name" >
</ListBox>
<Button Margin="10 >Select</Button>
<ListBox Width="100"></ListBox>
private List _foodList;
public List<FoodItem> FoodList
{
get { return _foodList; }
set { _foodList = value; }
}
private List<FoodItem> _newFoodList;
public List<FoodItem> NewFoodList
{
get { return _newFoodList; }
set { _newFoodList = value; }
}
public MainViewModel()
{
InitializeCommands();
GetFood();
}
private void GetFood()
{
FoodList = new List<FoodItem>()
{
new FoodItem() {Name="Applepie"},
new FoodItem() {Name="Scones"}
};
}
first, you need to replace the Lists with ObservableCollections, so that the UI can detect when new items are added.
Add a SelectedItem property to your ViewModel:
private FoodItem _selectedItem;
public FoodItem SelectedItem
{
get { return _selectedItem;}
set
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
bind the SelectedItem property of the 1st ListBox to this property:
<ListBox Width=" 100" x:Name="Firstbox"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedItem}" />
bind your 2nd ListBox to the NewFoodList property
create a command in your ViewModel:
private DelegateCommand _addItemCommand;
public ICommand AddItemCommand
{
get
{
if (_addItemCommand == null)
{
_addItemCommand = new DelegateCommand(AddItem);
}
return _addItemCommand;
}
}
void AddItem()
{
if (SelectedItem != null)
NewFoodList.Add(SelectedItem);
}
And finally, bind the button's Command property to the AddItemCommand property:
<Button Margin="10" Command="{Binding AddItemCommand}" >Select</Button>
I have the following MenuItem inside of a Context Menu in my WPF application:
<MenuItem Header="Email">
<MenuItem Command="Commands:CommandRepository.GenerateUserEmailCommand"
CommandParameter="{Binding Path=SelectedItems}"
Header="Email User">
</MenuItem>
<MenuItem Command="Commands:CommandRepository.GenerateManagerEmailCommand"
CommandParameter="{Binding Path=SelectedItems}"
Header="Email Manager">
</MenuItem>
</MenuItem>
The issue is that when both of the Email commands return CanExecute = false, and therefore both commands get disabled, the top-level MenuItem "Email" remains enabled. I know I could probably bind the IsEnabled of the top menu item to its Children property and then use a converter to decide when it should be disabled, but it seems like this should be happening automatically. Isn't this the whole point of using CommandBindings (i.e. they take care of IsEnabled for you)? Any better way to accomplish this?
I can think of two ways to do this:
1) If you don't mind code behind (I try to avoid it with WPF) you could just create an event handler for IsEnabledChanged that checks if the IsEnabled Property was set to false. If it was you could then do something like
ParentMenuItem.IsEnabled = ParentMenuItem.Items.Count( c => c is MenuItem && (c as MenuItem).IsEnabled == true) > 0
2) Create a ViewModel for the Parent MenuItem and Child MenuItem types and bind the is Enabled of the Parent MenuItem View to a IsEnabled property of the view model. The view model would return false using a similar
this.Children.Count(c => c.IsEnabled == true) > 0
why should your "Email" MenuItem become disabled? just because the childrens are?
i think your approach to use multibinding and a converter is a good way to do what YOU want.
Define a RootMenu command then add it to the root menu
Header="Email" Command="Commands:CommandRepository.RootMenu" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=.}"
Bind the command to the following RootMenuCanExecute
public static void DropDownMenuCanExecute(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = false;
ItemsControl parent = e.Parameter as ItemsControl;
if (parent.Items.Count == 0) { return; }
foreach (var i in parent.Items) {
ICommandSource cs = i as ICommandSource; if (cs==null) { continue; }
if (cs.Command == null) { continue; }
if (cs.Command.CanExecute(cs.CommandParameter)) { e.CanExecute = true; return; }
}
}
it is somewhat cpu expensive but it works.
Whatch out not to have too many MenuItem children