Búsqueda adecuada de DataGrid desde TextBox en WPF usando MVVM

Soy nuevo en el patrón de MVVM y estoy un poco confundido sobre cuándo usar Code Behind. Tengo una forma muy simple en este momento, que incluye un TextBox y un DataGrid. Lo que me gustaría es poder hacer que DataGrid cambie su ítem seleccionado basado en el TextBox.

He hecho esto en Code Behind y funciona bien usando el siguiente código:

private void textBox1_TextChanged(object sender, TextChangedEventArgs e) { for (int i = 0; i < dataGrid1.Items.Count; i++) { string cellContent = dtReferral.Rows[i][0].ToString(); try { if (cellContent != null && cellContent.Substring(0, textBox1.Text.Length).Equals(textBox1.Text)) { object item = dataGrid1.Items[i]; dataGrid1.SelectedItem = item; dataGrid1.ScrollIntoView(item); //row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); break; } } catch { } } } 

Ahora, solo quiero resaltar el elemento en la cuadrícula de datos que comienza con el texto en el cuadro de texto, y permitir que el usuario presione un botón para editar el elemento seleccionado.

¿Está bien tener esta lógica en el archivo Code Behind? ¿O tendría que hacer esto a través de algún tipo de enlace? Si debería hacer esto a través del modelo de vista con enlace, cualquier dirección sería apreciada. Gracias.

Si solo desea resaltar las celdas con el texto del TextBox texto, puede hacer que AttatchedProperty para DataGrid acepte su valor de búsqueda del TextBox y crear otro AttatchedProperty para la Cell para indicar una coincidencia que pueda usar para establecer las propiedades en el cuadro de texto. Estilo Cell Luego creamos un IMultiValueConverter para verificar el valor de Cell para una coincidencia con el Text búsqueda.

De esta forma es reutilizable en otros proyectos ya que solo necesita las AttachedProperties y el Converter

SearchValue AttachedProperty SearchValue a su propiedad TextBox Text .

   

A continuación, cree un Style para DataGridCell y cree un Setter para AttachedProperty IsTextMatch utilizando el IMultiValueConverter para devolver si el texto de las celdas coincide con SearchValue

         

Luego, podemos usar la propiedad IsTextMatch adjunta de IsTextMatch para establecer un resaltado usando un Trigger

  

Aquí hay un ejemplo de trabajo que muestra mis rambilings 🙂

Código:

 namespace WpfApplication17 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); for (int i = 0; i < 20; i++) { TestData.Add(new TestClass { MyProperty = GetRandomText(), MyProperty2 = GetRandomText(), MyProperty3 = GetRandomText() }); } } private string GetRandomText() { return System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName()); } private ObservableCollection _testData = new ObservableCollection(); public ObservableCollection TestData { get { return _testData; } set { _testData = value; } } } public class TestClass { public string MyProperty { get; set; } public string MyProperty2 { get; set; } public string MyProperty3 { get; set; } } public static class DataGridTextSearch { // Using a DependencyProperty as the backing store for SearchValue. This enables animation, styling, binding, etc... public static readonly DependencyProperty SearchValueProperty = DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(DataGridTextSearch), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits)); public static string GetSearchValue(DependencyObject obj) { return (string)obj.GetValue(SearchValueProperty); } public static void SetSearchValue(DependencyObject obj, string value) { obj.SetValue(SearchValueProperty, value); } // Using a DependencyProperty as the backing store for IsTextMatch. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsTextMatchProperty = DependencyProperty.RegisterAttached("IsTextMatch", typeof(bool), typeof(DataGridTextSearch), new UIPropertyMetadata(false)); public static bool GetIsTextMatch(DependencyObject obj) { return (bool)obj.GetValue(IsTextMatchProperty); } public static void SetIsTextMatch(DependencyObject obj, bool value) { obj.SetValue(IsTextMatchProperty, value); } } public class SearchValueConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string cellText = values[0] == null ? string.Empty : values[0].ToString(); string searchText = values[1] as string; if (!string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(cellText)) { return cellText.ToLower().StartsWith(searchText.ToLower()); } return false; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { return null; } } } 

Xaml:

             

Resultado:

enter image description hereenter image description here

Editar:

Si solo desea seleccionar la fila basada en una sola Columna, puede modificarla con bastante facilidad :).

Anule el estilo de DataGridRow lugar de DataGridCell .

   

Primer pase en la propiedad que desea en el IMultiValueConverter este debería ser su DataContext

     

A continuación, cambie el desencadenador para establecer IsSelected en la Row

  

Debería verse así:

         

Resultado:

enter image description here

He estado usando MVVM por un tiempo tranquilo, y todavía prefiero usar como una guía en lugar de una práctica estricta, en parte porque no siempre es práctico hacer todo en el patrón de MVVM exactamente, y aún más si no eres familiarizarse con eso.
Sugeriría que juegues con él hasta que encuentres la forma de MVVM que más te convenga.
No creo que sea tabú tener código en el código detrás del MVVM si el código está relacionado con la interfaz de usuario.
ScrollIntoView no es una propiedad de enlace, por lo que si desea vincularse a ella, deberá crear una propiedad de dependencia para manejar indirectamente el enlace. En cuanto a la configuración del elemento seleccionado, puede hacerlo a través de algo como:

Ver:

    

ViewModel:

  private string _selected = ""; public string Selected { get{ return _selected; } set { if(_selected == value) return; _selected = value; base.OnPropertyChanged("Selected"); } }