I wrote update function, I want to when I double-click a data in the listview, data will be shown in a textbox. I search and find many solutions,
I have a example:
`<ListView ItemsSource="{Binding listHocVien}"
SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}">
<ListView.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" />
</ListView.InputBindings>
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding Name}">
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>`
But I when I run the app and click data, I just need one click, not double-click.
I have to find the solution on the internet and didn't see anyone said to write an event for LeftDoubleClick.
So, did we need to write the event to LeftDoubleClick? If yes, can anyone show me examples.
Thank for all your help.
You could use behaviours:
How to add System.Windows.Interactivity to project?.
This way you could create a double click command and bind it to your view model class. In the execute of your command you could set the property of the textbox to the desired text
After you've added in your project you should reference the namespace in the xaml code. If you reference it as i then your code to add the behaviour to the list view should be as follows:
In your xaml:
<TextBox Text ="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
<ListView>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding YourCommand}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
In your View Model:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
public class SampleViewModel : INotifyPropertyChanged {
private string _Text;
public event PropertyChangedEventHandler PropertyChanged;
public string Text {
get { return _Text; }
set {
if (_Text != value) {
_Text = value;
RaisePropertyChanged();
}
}
}
public ICommand YourCommand { get; set; }
public SampleViewModel() {
YourCommand = new RelayCommand<TType>(YourCommandExecute); // that TType is the type of your elements in the listview
}
// Here I will assume that your TType has a property named Description
private void YourCommandExecute(TType selectedElement) {
Text = selectedItem.Description;
}
public void RaisePropertyChanged([CallerMemberName] propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Relay Command Implementation
// Simple Implementation of Generic Relay Command:
public class RelayCommand<T> : ICommand
{
private Action<T> execute;
private Func<T,bool> canExecute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<T> execute,Func<T,bool> canExecute=null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute((T)parameter);
}
public void Execute(object parameter)
{
execute((T)parameter);
}
}
Related
I have a problem with adding inputed text from TextBox_Scan to TextBox_SerialBuffer with key ENTER.
My code is not working correctly , issue is that text is copy on TextBox_SerialBuffer when i have some event , but i need to add when use key enter.
Add Class ViewModel in folder ViewsMoldel
<Window.DataContext>
<Viewsmodel:ViewModel/>
</Window.DataContext>
TextBox_Scan XAML :
<TextBox x:Name="TextBox_Scan"
HorizontalAlignment="Left"
Margin="173,165,0,0"
TextWrapping="NoWrap"
VerticalAlignment="Top"
Width="302"
FontSize="13"
KeyDown="TextBox_Scan_KeyDown"
FontFamily="Consolas"
FontWeight="Normal"
Text="{Binding Textadding, Mode=TwoWay}"
TextBox_SerialBuffer XAML :
<TextBox x:Name ="TextBox_SerialBuffer"
TextWrapping="Wrap"
TextAlignment="Justify"
Margin="1,1,1,1"
Background="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"
Padding="1"
FontFamily="Consolas"
FontSize="13"
Text="{Binding Textadding, Mode=TwoWay}"
Class ViewModel :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace New_Takaya.ViewsModel
{
public class ViewModel : INotifyPropertyChanged
{
private string _Text = "";
public event PropertyChangedEventHandler PropertyChanged;
public string Textadding
{
get { return _Text; }
set
{
_Text = value;
OnPropertyChanged("Textadding");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Help me please to solve this problem .
Thank you!
You bind the same Property Textadding (why not Text...?) to both TextBoxes. Therefore if you enter text into TextBox_Scan it immediatelly updates TextBox_SerialBuffer
use two separate Properties, define an inputbinding on your Textbox and Copy the Value in a command.
Something like:
<TextBox Text="{Binding Input, UpdateSourceTrigger=PropertyChanged }">
<TextBox.InputBindings>
<KeyBinding Key="Return"
CommandParameter="{Binding}"
Command="{Binding CopyValueCommand}" />
</TextBox.InputBindings>
</TextBox>
<TextBox Text="{Binding Output}" />
and corresponding ViewModel (I prefer PropertyChanged.Fody over manually implement INotifyPropertyChanged)
[PropertyChanged.AddINotifyPropertyChangedInterface]
class ViewModel4
{
public ViewModel4()
{
CopyValueCommand = new CopyCommand();
}
public string Input { get; set; }
public string Output { get; set; }
public ICommand CopyValueCommand { get; }
}
class CopyCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (parameter is ViewModel4 data)
{
data.Output = data.Input;
}
}
}
I have my MainWindow which has an ItemsControl for my EngineersUserControl (Engineers_UC) along with other controls. My Engineers_UC consists of a few TextBoxes for which I want to add MouseBinding with the aim of being able to left click on a TextBox and another method in my ViewModel to be executed. I have read that the issue might be that the elements of ItemsControl are not focusable but I haven't found a solution. Any ideas ?
MainWindow:
<Grid>
<StackPanel>
<UserControl:Ribbon_UC Loaded="Ribbon_UC_Loaded" Margin="0,0,0,70"/>
<UserControl:Calendar_UC/>
<ItemsControl ItemsSource="{Binding Engineer}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<UserControl:Engineers_UC />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
Engineers_UC:
<TextBox Name="EngineerName" IsReadOnly="True" Style="{StaticResource StyleTrigger} Text ="{Binding FULLNAME}">
<TextBox.InputBindings>
<MouseBinding Command="{Binding EngineerCommand}" CommandParameter="{Binding ElementName=EngineerName}" MouseAction="{Binding EngineerCommand.MouseGesture}"/>
</TextBox.InputBindings>
</TextBox>
EngineerCommand:
void RelayCommands()
{
EngineerCommand = new SimpleDelegateCommand(x => EngineerFunction(x))
{
MouseGesture = MouseAction.LeftClick
};
}
void EngineerFunction (object _engineername)
{
EngineerNameClicked = (_engineername as TextBox).Text;
}
public class SimpleDelegateCommand : ICommand
{
public Key GestureKey { get; set; }
public ModifierKeys GestureModifier { get; set; }
public MouseAction MouseGesture { get; set; }
Action<object> _executeDelegate;
public SimpleDelegateCommand(Action<object> executeDelegate)
{
_executeDelegate = executeDelegate;
}
public void Execute(object parameter)
{
_executeDelegate(parameter);
}
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
}
If the EngineerCommand command is defined in the same view model class as the collection to which you bind the ItemsSource property of the ItemsControl to (Engineer), you should use a RelativeSource for your binding(s) in the ItemTemplate:
<MouseBinding Command="{Binding DataContext.EngineerCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" ... />
I am using Exceed IntegerUpDown control in my .xaml file. I want to bind IntegerUpDown value as a CommandParameter of a button.
I do not have any code behind files and this is a custom control xaml file. So i want to achieve this by only using xaml systax.
<DockPanel>
<xctk:IntegerUpDown x:Name="ExtraExpressionValue" Increment="1" FormatString="N0" AllowSpin="True" Width="70" Watermark="Numeric" AllowTextInput="False" Minimum="0" Value="999"/>
<Button Style="{StaticResource ContextMenuButton}" Margin="5,0,0,0" Content="Add" Command="{Binding SetExtaExpressionValueCommand}" CommandParameter="{Binding ElementName=ExtraExpressionValue,Path=Value}"/>
</DockPanel>
Above is my xaml code. this return 0 to command method.
My command class is as follows,
public class DesignItemCommands
{
private ICommand setExtaExpressionValueCommand;
public ICommand SetExtaExpressionValueCommand => setExtaExpressionValueCommand ?? (setExtaExpressionValueCommand = new CommandHandler(SetExtaExpressionValue, canExecute));
private bool canExecute;
public DesignItemCommands()
{
canExecute = true;
}
private void SetExtaExpressionValue(object parameter)
{
//I need parameter here..
}
}
Couldn't find a way on the requirement. Just posting here to help someone later on this issue.
I used a ViewModel Variable to bind IntegerUpDown control value.
<DockPanel>
<xctk:IntegerUpDown Increment="1" Value="{Binding ExtraExpressionValue}"/>
<Button Content="Add" Command="{Binding SetExtaExpressionValueCommand}"/>
</DockPanel>
My ViewModel is as follows,
public class DesignItemCommands
{
private ICommand setExtaExpressionValueCommand;
public ICommand SetExtaExpressionValueCommand => setExtaExpressionValueCommand ?? (setExtaExpressionValueCommand = new CommandHandler(SetExtaExpressionValue, canExecute));
private bool canExecute;
public int ExtraExpressionValue { get; set; }
public DesignItemCommands()
{
canExecute = true;
ExtraExpressionValue = 1;
}
private void SetExtaExpressionValue(object parameter)
{
//I can use value here using variable ExtraExpressionValue
}
}
Hope this helps someone later.
I'm doing my first app using MVVM. I have in "View" declared Datagrid. Code XAML below:
<DataGridTemplateColumn Header="delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type> UserControl},Mode=FindAncestor}, Path=DataContext.ClickCommand}"> Content="X" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>>
</DataGrid>
In my ViewModel class I can run function that I want after click button "delete" by part of code:
public ICommand ClickCommand => _clickCommand ?? (_clickCommand = new CommandHandler(Delete, _canExecute));
public void Delete()
{
// DataTable.Rows.RemoveAt();
}
I have problem because I can't get index of selectet row. Source of data in datagrid is dataTable.
Do you have any ideas how to do this?
I've tried something with passing parameter with command of button but I coudn't make it works.
Xmal code
<Button Command="{Binding Path=DataContext.ViewCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding Id}" Content="X" Background="Chocolate"/>
Codebehind code
public RelayCommand DeleteCommand
{
get
{
return new RelayCommand(p => Delete(p));
}
}
public void Delete(string id)
{
// DataTable.Rows.RemoveAt();
}
This is example you can pass whatever you want in that cmd parameter.
Relay cmd
public class RelayCommand : ICommand
{
private Action<object> action;
private Func<bool> canFuncPerform;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<object> executeMethod)
{
action = executeMethod;
}
public RelayCommand(Action<object> executeMethod, Func<bool> canExecuteMethod)
{
action = executeMethod;
canFuncPerform = canExecuteMethod;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
if (canFuncPerform != null)
{
return canFuncPerform();
}
if (action != null)
{
return true;
}
return false;
}
public void Execute(object parameter)
{
if (action != null)
{
action(parameter);
}
}
}
You shouldn't rely on the selected item. Instead pass the current row item as CommandParameter:
<DataGridTemplateColumn Header="delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}, Path=DataContext.ClickCommand}"
CommandParameter="{Binding}"
Content="X" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Then of course, use an ICommand implementation that is not discarding the command parameter and use it to identify the row to be deleted.
I have binding ObservableCollection - DataGrid (mode - TwoWay), but i want update collection by myself with UpdateSource() call and disable automathic source updating. I set binding like
ItemsSource="{Binding Path=Bezier.BezierPoints, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
but my collection still updates automathically. My code samples are below. What am i doing wrong?
My XAML:
<DataGrid Name="BezierPointsDataGrid" Margin="5" AutoGenerateColumns="False"
Grid.Column="0" Grid.Row="0" Background="White"
ItemsSource="{Binding Path=Bezier.BezierPoints, Mode=TwoWay, UpdateSourceTrigger=Explicit}">
<DataGrid.Columns>
<DataGridTextColumn Header="X" Binding="{Binding Path=X}" Width="1*"/>
<DataGridTextColumn Header="Y" Binding="{Binding Path=Y}" Width="1*"/>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=UpdateBezierPointsCommand}" CommandParameter="{Binding ElementName=BezierPointsDataGrid}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
My ViewModel:
class BezierCurveViewModel : INotifyPropertyChanged
{
#region Bezier curve model
private BezierCurveModel _bezier;
public BezierCurveModel Bezier
{
get { return _bezier; }
set
{
if (_bezier == value)
return;
_bezier = value;
OnPropertyChanged("Bezier");
}
}
#endregion
#region Commands
public ICommand UpdateBezierPointsCommand { set; get; }
#endregion
#region Constructor
public BezierCurveViewModel()
{
UpdateBezierPointsCommand = new Command(a => ((DataGrid)a).GetBindingExpression(DataGrid.ItemsSourceProperty).UpdateSource());
Bezier = new BezierCurveModel();
}
#endregion
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
My model:
public ObservableCollection<DPoint> BezierPoints { private set; get; }
EDIT: I changed ObservableCollection To DataTable to achieve expected behaviour. But i am still interested in solving this problem because i want to understand why any binding to observable collection updates source after editing table (read my comment to Andrew's post).
Here, you have set up the view to update the BezierPoints property explicitly, since that is what you are binding the ItemsSource.
I will assume that what you actually want is to use an Explicit update trigger on the properties of the individual points. To do this, you need to change the DataGridTextColum binding to UpdateSourceTrigger=Explicit.
As a side note, it would seem impossible that you could ever update the BezierPoints collection from the View at all because the property has a private setter.