SO i have simple ListView with binding:
View model:
ObservableCollection<ClipboardItem> Clipboards;
ListView:
<ListView Name="ListViewUsers"
ItemsSource="{Binding Clipboards}"/>
<ListView.View>
<GridView >
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid>
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Margin="0,0,0,0"/>
</Grid>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
And all my non english text (Hebrew) is display as ???
Any suggestions how to fix it ?
Edit
I added my ClipboardItem class:
public class ClipboardItem
{
public string Text { get; set; }
}
I also add my Clipboard event:
private void ClipboardMonitor_OnClipboardContentChanged(object sender, EventArgs e)
{
string clipboardText = Clipboard.GetText(TextDataFormat.Text);
viewModel.Clipboards.Add(new ClipboardItem { Text = clipboardText });
}
ClipboardMonitor:
public sealed class ClipboardMonitor : IDisposable
{
private static class NativeMethods
{
/// <summary>
/// Places the given window in the system-maintained clipboard format listener list.
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddClipboardFormatListener(IntPtr hwnd);
/// <summary>
/// Removes the given window from the system-maintained clipboard format listener list.
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
/// <summary>
/// Sent when the contents of the clipboard have changed.
/// </summary>
public const int WM_CLIPBOARDUPDATE = 0x031D;
/// <summary>
/// To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function.
/// </summary>
public static IntPtr HWND_MESSAGE = new IntPtr(-3);
}
private HwndSource hwndSource = new HwndSource(0, 0, 0, 0, 0, 0, 0, null, NativeMethods.HWND_MESSAGE);
public ClipboardMonitor()
{
hwndSource.AddHook(WndProc);
NativeMethods.AddClipboardFormatListener(hwndSource.Handle);
}
public void Dispose()
{
NativeMethods.RemoveClipboardFormatListener(hwndSource.Handle);
hwndSource.RemoveHook(WndProc);
hwndSource.Dispose();
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeMethods.WM_CLIPBOARDUPDATE)
{
OnClipboardContentChanged?.Invoke(this, EventArgs.Empty);
}
return IntPtr.Zero;
}
/// <summary>
/// Occurs when the clipboard content changes.
/// </summary>
public event EventHandler OnClipboardContentChanged;
}
edit
private ClipboardMonitor clipboardMonitor;
public MainWindow()
{
InitializeComponent();
InitiateClipboardMonitor();
}
private void InitiateClipboardMonitor()
{
clipboardMonitor = new ClipboardMonitor();
clipboardMonitor.OnClipboardContentChanged += ClipboardMonitor_OnClipboardContentChanged;
}
Changed the TextDataFormat.Text to TextDataFormat.UnicodeText
private void ClipboardMonitor_OnClipboardContentChanged(object sender, EventArgs e)
{
string clipboardText = Clipboard.GetText(TextDataFormat.UnicodeText);
Clipboards.Add(new ClipboardItem { Text = clipboardText });
}
Related
I have a DataGrid and want to pass the AlternationIndex to the bound element (off the current object).
CellTemplate
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock HorizontalAlignment="Center" Text="{Binding Index}"/>
<i:Interaction.Behaviors>
<behaviors:RoutePropertyValue
Source="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=(ItemsControl.AlternationIndex)}"
Target="{Binding Index, Mode=TwoWay}"/>
</i:Interaction.Behaviors>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
*RoutePropertyValueBehavior**
public class RoutePropertyValue : Behavior<FrameworkElement>
{
/// <summary>
/// The source property value
/// </summary>
public object Source
{
get => (object)GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
/// <summary>
/// The <see cref="Source"/> DependencyProperty.
/// </summary>
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(RoutePropertyValue), new PropertyMetadata(null, SourceChangedCallback));
private static void SourceChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (d is RoutePropertyValue instance)
{
instance.OnSourceChanged();
}
}
protected virtual void OnSourceChanged()
{
Target = Source;
}
/// <summary>
/// The target where the value should be writetn
/// </summary>
public object Target
{
get => (object)GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}
/// <summary>
/// The <see cref="Target"/> DependencyProperty.
/// </summary>
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(object), typeof(RoutePropertyValue), new PropertyMetadata(null));
}
Actually the Target is always null when debugging. Also if changing the order inside of the DataGrid, the SourceChangedCallback is not getting called again. So anyways it seems to be the wrong way to 'tunnel' property values to another property.
You could bind to the target object and then specify which source property you want to set. You should try to set the source property whenever any of the target properties are set. Try this:
public class RoutePropertyValue : Behavior<FrameworkElement>
{
public object Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source), typeof(object),
typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
if (d is RoutePropertyValue instance)
instance.OnAnyValueChanged();
}
protected virtual void OnAnyValueChanged()
{
if (!string.IsNullOrEmpty(TargetMember))
TargetObject?.GetType().GetProperty(TargetMember)?.SetValue(TargetObject, Source);
}
public object TargetObject
{
get => GetValue(TargetObjectProperty);
set => SetValue(TargetObjectProperty, value);
}
public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register(nameof(TargetObject), typeof(object),
typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
public string TargetMember
{
get => (string)GetValue(TargetMemberProperty);
set => SetValue(TargetMemberProperty, value);
}
public static readonly DependencyProperty TargetMemberProperty = DependencyProperty.Register(nameof(TargetMember), typeof(string),
typeof(RoutePropertyValue), new PropertyMetadata(null, Callback));
}
XAML:
<behaviors:RoutePropertyValue
TargetObject="{Binding}"
TargetMember="Index"
Source="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=(ItemsControl.AlternationIndex)}"
/>
wpf c# side MainWindow call the yenikaytekle window to take the perperty,I i use the ado.net data model to fill the list view at xaml file.
public MainWindow()
{
InitializeComponent();
FillMarkaListView();
}
/// <summary>
/// fill the list view
/// </summary>
public void FillMarkaListView()
{
//get list of all marka
List<MARKA> listOfMarka = dbContext.MARKA.ToList();
lvMarka.ItemsSource = listOfMarka;
}
/// <summary>
/// add new item to marak table,with open new window to give marka name
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnYeniMarkaEkle_Click(object sender, RoutedEventArgs e)
{
//here open new window to take the details of model
YeniMarkaEkle saveWindow = new YeniMarkaEkle();
saveWindow.ShowDialog();
}
}
the another window to take the details of model,here i call the window to take the property of model and save the data in database
public partial class YeniMarkaEkle : Window
{
private BaburTechEntities dbContext = new BaburTechEntities();
public YeniMarkaEkle()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
txtMarka.SelectAll();
txtMarka.Focus();
}
/// <summary>
/// add new marka to the table
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDialogOk_Click(object sender, RoutedEventArgs e)
{
MARKA mARKA = new MARKA();
mARKA.ADI = txtMarka.Text.ToUpper();
dbContext.MARKA.Add(mARKA);
dbContext.SaveChanges();
this.Close();
}
}
here is my main window xaml code
<!-- List of marka-->
<StackPanel Grid.Row="1" Margin="10">
<Grid>
<ListView Margin="10" x:Name="lvMarka" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Kategori ID" Width="200" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Kategori" Width="200" DisplayMemberBinding="{Binding ADI}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</StackPanel>
If you want to get your updated list you should call dbContext.MARKA.ToList() again after you call saveWindow.ShowDialog(); and set it to your listView itemssource but you should read about MVVM because what you are doing here doesn't follow good practices.
EDIT:
private List<MARKA> listOfMarka
public MainWindow()
{
listOfMarka= new List<MARKA>();
InitializeComponent();
FillMarkaListView();
}
private List<MARKA> listOfMarka
/// <summary>
/// fill the list view
/// </summary>
public void FillMarkaListView()
{
//get list of all marka
listOfMarka = dbContext.MARKA.ToList();
lvMarka.ItemsSource = listOfMarka;
}
/// <summary>
/// add new item to marak table,with open new window to give marka name
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnYeniMarkaEkle_Click(object sender, RoutedEventArgs e)
{
//here open new window to take the details of model
YeniMarkaEkle saveWindow = new YeniMarkaEkle(listOfMarka);
saveWindow.ShowDialog();
lvMarka.ItemsSource = listOfMarka;
}
public partial class YeniMarkaEkle : Window
{
private BaburTechEntities dbContext = new BaburTechEntities();
private List<MARKA> listOfMarka;
public YeniMarkaEkle(List<MARKA> listOfMarka)
{
listOfMarka = listOfMarka;
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
txtMarka.SelectAll();
txtMarka.Focus();
}
/// <summary>
/// add new marka to the table
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDialogOk_Click(object sender, RoutedEventArgs e)
{
MARKA mARKA = new MARKA();
mARKA.ADI = txtMarka.Text.ToUpper();
listOfMarka.Add(mARKA);
dbContext.MARKA.Add(mARKA);
dbContext.SaveChanges();
this.Close();
}
I am using Caliburn.Micro for a WPF application.
One of the feature I am using wraps a view in the a popup control and let me choose the settings.
But I came to the conclusion that this is a behaviour I cannot solve.
In the code behind when I click the Button a popup appears and when I click elsewhere on the screen it goes away as expected.
When I click on an item in the list, the popup appears but does not disappear if I click elsewhere on the window. (it does though if i click somewhere else, like another application)
Basically I cannot create a PopUp with StaysOpen = false behaviour when handling a selected item event. What can i do to solve this?
<Window x:Class="WpfApplication1.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left" SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid>
</Window>
and the code behind
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = this.ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = selection.Name , MinWidth = 200 , MinHeight = 32};
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = "This is button Clicked" , MinWidth = 200, MinHeight = 32 };
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
}
Hi please try the next solution. It based on the mouse down event hooking (from here), each time it happened will collapse the Popup(and reset list item selection).
Code behind
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(
"Selected", typeof (object), typeof (MainWindow), new PropertyMetadata(default(object)));
//property to monitor selection
public object Selected
{
get { return (object) GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
private Popup _popUp;
public MainWindow()
{
InitializeComponent();
_popUp = new Popup {IsOpen = false};
ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
//will stop hookig here
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
Unloaded -= OnUnloaded;
Loaded -= OnLoaded;
MouseHook.MouseAction -= MouseHookOnMouseAction;
MouseHook.Stop();
}
//will collapse the popup and reset selection
private void MouseHookOnMouseAction(object sender, EventArgs eventArgs)
{
Selected = null;
_popUp.IsOpen = false;
}
//will start hookig here
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
MouseHook.MouseAction += MouseHookOnMouseAction;
MouseHook.Start();
}
//here is your logic without any changes
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
_popUp.Child = new TextBox { Text = selection.Name, MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
//here is your logic without any changes
private void Button_Click(object sender, RoutedEventArgs e)
{
_popUp.IsOpen = false;
_popUp.Child = new TextBox { Text = "This is button Clicked", MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Mouse hooking helper
/// </summary>
public static class MouseHook
{
public static event EventHandler MouseAction = delegate { };
/// <summary>
/// Starts hooking
/// </summary>
public static void Start()
{
_hookID = SetHook(_proc);
}
/// <summary>
/// Stops hooking
/// </summary>
public static void Stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
//actually set a hook
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
return hook;
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
//is the mouse hook callback
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
XAML code
<Window x:Class="WPFPopupStrangeIssueSOHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left"
SelectedItem="{Binding ElementName=This, Path=Selected, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid></Window>
Let me know if you need any explanations.
Regards.
I have a problem with binding in KeyBinding in WPF. I'm developing .net 3.5 project using WPF with MVVM pattern. I have to fire command whenever some letter will be typed. Unfortunately Command and CommandParameter aren't Dependency Properties in this .net version and i can't bind to them. So I've written attached properties to assign command and command parameter from my view model. But binding to them isn't working, when I change binding to text (in command parameter) CommandBindingParameterChanged will rise but it doesn't when there is binding to parameter. I tired to set window's name and pass that to binding but it also didn't work. But when I'll assign the same command to button it works fine. Here is my code snippet:
Attached properties:
public class Helper
{
public static readonly DependencyProperty CommandBindingProperty = DependencyProperty.RegisterAttached("CommandBinding", typeof(ICommand), typeof(Helper), new FrameworkPropertyMetadata(default(ICommand), FrameworkPropertyMetadataOptions.None, CommandChanged));
public static ICommand GetCommandBinding(DependencyObject o)
{
return (ICommand)o.GetValue(CommandBindingProperty);
}
public static void SetCommandBinding(DependencyObject o, ICommand value)
{
o.SetValue(CommandBindingProperty, value);
}
private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var input = d as InputBinding;
input.Command = (ICommand)e.NewValue;
}
public static readonly DependencyProperty CommandBindingParameterProperty = DependencyProperty.RegisterAttached("CommandBindingParameter", typeof(object), typeof(Helper), new PropertyMetadata(CommandParameterChanged));
private static void CommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var input = d as InputBinding;
if (input != null)
input.CommandParameter = e.NewValue;
}
public static object GetCommandBindingParameter(DependencyObject o)
{
return o.GetValue(CommandBindingParameterProperty);
}
public static void SetCommandBindingParameter(DependencyObject o, object value)
{
o.SetValue(CommandBindingParameterProperty, value);
}
}
ViewModel
public class MainWindowViewModel : ViewModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
private bool _parameter;
public bool Parameter
{
get { return _parameter; }
set
{
_parameter = value;
RaisePropertyChanged("Parameter");
}
}
public MainWindowViewModel()
{
Parameter = true;
}
private RelayCommand<bool> _someCommand;
public ICommand SomeCommand
{
get { return _someCommand ?? (_someCommand = new RelayCommand<bool>(Execute, CanExecute)); }
}
private bool CanExecute(bool arg)
{
return arg;
}
private void Execute(bool obj)
{
//do something
}
}
XAML:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:Test"
Name="Window"
DataContext="{Binding Main, Source={StaticResource Locator}}"
>
<Grid>
<StackPanel>
<TextBox Text="{Binding Text}">
<TextBox.InputBindings>
<KeyBinding Key="A" local:Helper.CommandBinding="{Binding DataContext.SomeCommand, ElementName=Window}" local:Helper.CommandBindingParameter="{Binding DataContext.Parameter, ElementName=Window}"/>
</TextBox.InputBindings>
</TextBox>
<Button Content="SomeButton" Command="{Binding SomeCommand}" CommandParameter="{Binding Parameter}"/>
</StackPanel>
</Grid>
you may want to try this solution.
Use Blend 3 Interactions, i.e. Add System.Windows.Interactivity & Microsoft.Expression.Interactions.dll as reference into your project. I have tested the changes below. Execute method (defined in ViewModel) is called the movement textbox is keyed in.
Modified XAML:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:Test"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Name="Window">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<TextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<local:CommandAction Command="{Binding Path=SomeCommand}" CommandParameter="{Binding Path=Parameter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</StackPanel>
</Grid>
</Window>
CommandAction.CS: Instead of Helper, use CommandAction. CommandAction is found at this location
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using Microsoft.Expression.Interactivity;
using System.Windows.Interactivity;
namespace Test
{
/// <summary>
/// The CommandAction allows the user to route a FrameworkElement's routed event to a Command.
/// For instance this makes it possible to specify--in Xaml--that right-clicking on a Border
/// element should execute the Application.Close command (this example may not make much sense,
/// but it does illustrate what's possible).
///
/// CommandParameter and CommandTarget properties are provided for consistency with the Wpf
/// Command pattern.
///
/// The action's IsEnabled property will be updated according to the Command's CanExecute value.
///
/// In addition a SyncOwnerIsEnabled property allows the user to specify that the owner element
/// should be enabled/disabled whenever the action is enabled/disabled.
/// </summary>
public class CommandAction : TargetedTriggerAction<FrameworkElement>, ICommandSource
{
#region Properties to Expose
[Category("Command Properties")]
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(CommandAction), new PropertyMetadata(
(ICommand)null, OnCommandChanged));
[Category("Command Properties")]
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter", typeof(object), typeof(CommandAction), new PropertyMetadata());
[Category("Command Properties")]
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
"CommandTarget", typeof(IInputElement), typeof(CommandAction), new PropertyMetadata());
[Category("Command Properties")]
public bool SyncOwnerIsEnabled
{
get { return (bool)GetValue(SyncOwnerIsEnabledProperty); }
set { SetValue(SyncOwnerIsEnabledProperty, value); }
}
/// <summary>
/// When SyncOwnerIsEnabled is true then changing CommandAction.IsEnabled will automatically
/// update the owner (Target) IsEnabled property.
/// </summary>
public static readonly DependencyProperty SyncOwnerIsEnabledProperty = DependencyProperty.Register(
"SyncOwnerIsEnabled", typeof(bool), typeof(CommandAction), new PropertyMetadata());
#endregion
#region Command implementation
/// <summary>
/// This is a strong reference to the Command.CanExecuteChanged event handler. The commanding
/// system uses a weak reference and if we don't enforce a strong reference then the event
/// handler will be gc'ed.
/// </summary>
private EventHandler CanExecuteChangedHandler;
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var action = (CommandAction)d;
action.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
}
private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
{
if (oldCommand != null)
UnhookCommand(oldCommand);
if (newCommand != null)
HookCommand(newCommand);
}
private void UnhookCommand(ICommand command)
{
command.CanExecuteChanged -= CanExecuteChangedHandler;
UpdateCanExecute();
}
private void HookCommand(ICommand command)
{
// Save a strong reference to the Command.CanExecuteChanged event handler. The commanding
// system uses a weak reference and if we don't save a strong reference then the event
// handler will be gc'ed.
CanExecuteChangedHandler = new EventHandler(OnCanExecuteChanged);
command.CanExecuteChanged += CanExecuteChangedHandler;
UpdateCanExecute();
}
private void OnCanExecuteChanged(object sender, EventArgs e)
{
UpdateCanExecute();
}
private void UpdateCanExecute()
{
if (Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
IsEnabled = command.CanExecute(CommandParameter, CommandTarget);
else
IsEnabled = Command.CanExecute(CommandParameter);
if (Target != null && SyncOwnerIsEnabled)
Target.IsEnabled = IsEnabled;
}
}
#endregion
protected override void Invoke(object o)
{
if (Command != null)
{
var command = Command as RoutedCommand;
if (command != null)
command.Execute(CommandParameter, CommandTarget);
else
Command.Execute(CommandParameter);
}
}
}
}
Screenshot: if System.Windows.Interactivity & Microsoft.Expression.Interactions.dll are missing in your environment, please install blend. Blend is very easy to isntall and Installation doesn't take much time.
in general TextBox control TextChanged event is working but in ItemsControl, the TextBox TextChanged Event is not fired how can i do this. I trying to do by using following code which I have implemented but not getting result which I want.
So, what am I doing wrong?
View
<Window x:Class="SoniSoft.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ff="clr-namespace:SoniSoft"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<ff:ViewModels/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="38"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" ff:TextBoxBehaviour.TextChangedCommand="{Binding TextChanged}" />
<ItemsControl Margin="7,0,0,0" Grid.Row="3" ItemsSource="{Binding Path=ViewModelSearchResults}" x:Name="list">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Grid>
<TextBox ff:TextBoxBehaviour.TextChangedCommand="{Binding TextChanged}" Text="{Binding Path=CategoryName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="14" FontWeight="Normal" x:Name=" TextBoxCategoryName" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
View Models
class ViewModels :ViewModelBase
{
public ObservableCollection<Category> AllCategorys = new ObservableCollection<Category>();
DatabaseDataContext db = new DatabaseDataContext();
private ListCollectionView _objViewModelSearchResults;
public ListCollectionView ViewModelSearchResults
{
get { return _objViewModelSearchResults; }
set
{
_objViewModelSearchResults = value;
OnPropertyChanged("ViewModelSearchResults");
}
}
public ViewModels()
{
AllCategorys.Clear();
foreach (var item in db.Categories.OrderBy(c => c.CategoryName))
{
AllCategorys.Add(item);
}
ViewModelSearchResults = new ListCollectionView(AllCategorys);
}
public ICommand TextChanged
{
get
{
// this is very lazy: I should cache the command!
return new TextChangedCommand();
}
}
private class TextChangedCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show("Text Changed");
}
public bool CanExecute(object parameter)
{
return true;
}
}
}
DependencyProperty
class EventBehaviourFactory
{
public static DependencyProperty CreateCommandExecutionEventBehaviour(RoutedEvent routedEvent, string propertyName, Type ownerType)
{
DependencyProperty property = DependencyProperty.RegisterAttached(propertyName, typeof(ICommand), ownerType,
new PropertyMetadata(null,
new ExecuteCommandOnRoutedEventBehaviour(routedEvent).PropertyChangedHandler));
return property;
}
private class ExecuteCommandOnRoutedEventBehaviour : ExecuteCommandBehaviour
{
private readonly RoutedEvent _routedEvent;
public ExecuteCommandOnRoutedEventBehaviour(RoutedEvent routedEvent)
{
_routedEvent = routedEvent;
}
/// <summary>
/// Handles attaching or Detaching Event handlers when a Command is assigned or unassigned
/// </summary>
/// <param name="sender"></param>
/// <param name="oldValue"></param>
/// <param name="newValue"></param>
protected override void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue)
{
UIElement element = sender as UIElement;
if (element == null) { return; }
if (oldValue != null)
{
element.RemoveHandler(_routedEvent, new RoutedEventHandler(EventHandler));
}
if (newValue != null)
{
element.AddHandler(_routedEvent, new RoutedEventHandler(EventHandler));
}
}
protected void EventHandler(object sender, RoutedEventArgs e)
{
HandleEvent(sender, e);
}
}
internal abstract class ExecuteCommandBehaviour
{
protected DependencyProperty _property;
protected abstract void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue);
protected void HandleEvent(object sender, EventArgs e)
{
DependencyObject dp = sender as DependencyObject;
if (dp == null)
{
return;
}
ICommand command = dp.GetValue(_property) as ICommand;
if (command == null)
{
return;
}
if (command.CanExecute(e))
{
command.Execute(e);
}
}
/// <summary>
/// Listens for a change in the DependencyProperty that we are assigned to, and
/// adjusts the EventHandlers accordingly
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void PropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// the first time the property changes,
// make a note of which property we are supposed
// to be watching
if (_property == null)
{
_property = e.Property;
}
object oldValue = e.OldValue;
object newValue = e.NewValue;
AdjustEventHandlers(sender, oldValue, newValue);
}
}
}
class TextBoxBehaviour
{
public static readonly DependencyProperty TextChangedCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(TextBox.TextChangedEvent, "TextChangedCommand", typeof(TextBoxBehaviour));
public static void SetTextChangedCommand(DependencyObject o, ICommand value)
{
o.SetValue(TextChangedCommand, value);
}
public static ICommand GetTextChangedCommand(DependencyObject o)
{
return o.GetValue(TextChangedCommand) as ICommand;
}
}
Here is the problem. You are setting the command in an ItemTemplate. Thus it is binding to the Category object you have in the ListCollectionView. Now this is the object that doesnt contain any command for your text changed. What does contain the command for your TextChanged is the DataContext of the UserControl and you need to bind it to that.
Now there are is a way to work around and its called Ancestor RelativeSource. As I work with silverlight it might work different but this line of code should do.
Edit:
The actual line should be. this because it is ofcourse a window and you need to have the DataContext (the viewmodel) and then the property TextChanged:
<TextBox ff:TextBoxBehaviour.TextChangedCommand="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Path=DataContext.TextChanged}" />