How to hookup TextBox's TextChanged event and

2020-02-09 06:51发布

Recently, I realized that MVVM pattern is so useful for Silverlight application and studying how to adopt it into my project.

BTW, how to hook up the textbox's textChanged event with Command? There is Command property for Button, however Textbox has no commapd property. If Controls don't have command property, how to combine ICommand and Control's event?

I got following xaml code

<UserControl.Resources>
        <vm:CustomerViewModel x:Key="customerVM"/>    
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" 
          Background="White" 
          DataContext="{Binding Path=Customers, Source={StaticResource customerVM}, Mode=TwoWay}" >

        <StackPanel>
            <StackPanel Orientation="Horizontal"
                        Width="300"
                        HorizontalAlignment="Center">
                <TextBox x:Name="tbName" 
                         Width="50" 
                         Margin="10"/>
                <Button Width="30" 
                        Margin="10" 
                        Content="Find"
                        Command="{Binding Path=GetCustomersByNameCommand, Source={StaticResource customerVM}}"
                        CommandParameter="{Binding Path=Text, ElementName=tbName}"/>
            </StackPanel>
            <sdk:DataGrid ItemsSource="{Binding Path=DataContext, ElementName=LayoutRoot}"
                          AutoGenerateColumns="True"
                          Width="300"
                          Height="300"/>
        </StackPanel>
    </Grid>

What I am trying to do is that if user input some text in the textbox, data will be shown in the datagrid instead of using button click. I know there is autocomplete box control built in. however, I want to know how to call Command property in the ViewModel class in the controls which does not have Command property such as textbox.

Thanks

10条回答
劫难
2楼-- · 2020-02-09 07:29

Jeremy answered it. However, if you want to reduce code behind just do something like this. In your view model:

public class MyViewModel 
{
    private string _myText;

    public string MyText 
    {
        get { return _myText; }
        set 
        {
            _myText = value;
            RaisePropertyChanged("MyText"); // this needs to be implemented
            // now do whatever grid refresh/etc
        }
    }
    public void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
        binding.UpdateSource();
    }
}

Then in code behind:

public void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    YourViewModel.TextBox_TextChanged(sender, e);
}

I know it's duplicated code, but if this is what you want, then here it is.

查看更多
看我几分像从前
3楼-- · 2020-02-09 07:33

Here's the easiest way. Bind your text box to the property on the view model, as you described above. Then, simply add a code-behind (yes, I'm talking code-behind with MVVM, it's not the end of the world) event to the Text Box. Add a TextChanged event, then simply refresh the binding.

Altogether, you'll have something like this for a view model:

public class MyViewModel 
{
    private string _myText;

    public string MyText 
    {
        get { return _myText; }
        set 
        {
            _myText = value;
            RaisePropertyChanged("MyText"); // this needs to be implemented
            // now do whatever grid refresh/etc
        }
    }
}

In your XAML, you'll have this:

<TextBox Text="{Binding MyText,Mode=TwoWay}" TextChanged="TextBox_TextChanged"/>

Finally, in the code behind, simply do this:

public void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
   var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
   binding.UpdateSource();
}

That will cause your property to update anytime the text changes. }

查看更多
Fickle 薄情
4楼-- · 2020-02-09 07:34

I solved it by binding to a property on my view model and setting the binding's UpdateSourceTrigger to PropertyChanged. The property supports INotifyPropertyChanged.

In my view model I then subscribe to the PropertyChanged event for the property. When it triggers I perform the tasks I need to do (in my case updating a collection) and at the end I call PropertyChanged on the property that my other stuff in the view is listening to.

查看更多
趁早两清
5楼-- · 2020-02-09 07:36

Here's the MvvmLight way of doing it! Credit goes to GalaSoft Laurent Bugnion.

<sdk:DataGrid Name="dataGrid1" Grid.Row="1"
    ItemsSource="{Binding Path=CollectionView}"
    IsEnabled="{Binding Path=CanLoad}"
    IsReadOnly="True">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <cmd:EventToCommand
                Command="{Binding SelectionChangedCommand}"
                CommandParameter="{Binding SelectedItems, ElementName=dataGrid1}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</sdk:DataGrid>

Source: http://blog.galasoft.ch/archive/2010/05/19/handling-datagrid.selecteditems-in-an-mvvm-friendly-manner.aspx

查看更多
三岁会撩人
6楼-- · 2020-02-09 07:40

I had the same question. Then I find this article.

http://deanchalk.com/wpf-mvvm-property-changed-command-behavior/

  1. Create behavior (behavior recive value to changend event and command to changend)
  2. Implement behavior in your WPF
  3. Bind Behavior your command to a ValueChanged
查看更多
疯言疯语
7楼-- · 2020-02-09 07:45

For the sake of conversation, lets say that you do need to hook up some arbitrary event to a Command rather than bind directly to a property on the ViewModel (due to a lack of support in the control or framework, defect, etc.) This can be done in the codebehind. Contrary to some misconceptions, MVVM does not preclude codebehind. It is just important to remember that the logic in the codebehind should not cross layers - it should be relate directly to the UI and the specific UI technology being used. (Note however, that putting 95% of your work in the markup file may make it a little unintutitive to have some functionality in the codebehind, so a comment or two in the markup about this one-off codebehind implementation may make things easier down the road for yourself or others.)

There are usually 2 parts to binding a command in codebehind. First, you have to respond to the event. Second, you (may) want to tie into the command's CanExecute property.

// Execute the command from the codebehind
private void HandleTheEvent(Object sender, EventArgs e)
{
    var viewModel = DataContext as ViewModel;
    if (viewModel != null)
    {
        var command = viewModel.SomeCommand;
        command.Execute(null);
    }
}

// Listen for the command's CanExecuteChanged event
// Remember to call this (and unhook events as well) whenever the ViewModel instance changes
private void ListenToCommandEvent()
{
    var viewModel = DataContext as ViewModel;
    if (viewModel != null)
    {
        var command = viewModel.SomeCommand;
        command.CanExecuteChanged += (o, e) => EnableOrDisableControl(command.CanExecute(null));
    }
}
查看更多
登录 后发表回答